home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PsL Monthly 1993 December
/
PSL Monthly Shareware CD-ROM (December 1993).iso
/
prgmming
/
dos
/
c
/
flxlstc.exe
/
FLC2.DOC
< prev
next >
Wrap
Text File
|
1992-07-12
|
193KB
|
6,002 lines
FLC2 is shareware meaning try before you buy. If you use FLC2
for other than evaluation purposes you are required to register.
The registration fee is $65. Upon registration you will be sent a
hard copy manual and 3.5" DOS formatted diskette with the latest
revisions and examples. Thank you for supporting the shareware concept!
FlexList for ANSI C
Copyright 1990
John W. Small
All rights reserved
PSW / Power SoftWare
P.O. Box 10072
McLean, Virginia 22102 8072
(703) 759-3838
10/4/90
CLAIM TO PROPRIETARY TECHNIQUES
Several features of FlexList used in combination make FlexList
unique and versatile. The hybrid stack-queue-list-array data
structure and the techniques used to implement it as a generic
polymorphic object can be easily ported to other computer
languages and remain intact in their essence. The author claims
all rights to these features.
Software License Agreement
Power SoftWare licenses the bona fide purchaser of FlexList to
use the tool in the development of software without royalty. The
licensee may not publish any portion of the tool kit and may only
make backup copies of software and documentation as a means of
protecting the licensee's investment against loss or damage.
Limited Warranty
Power SoftWare warrants the FlexList toolkit to be free from
defects in materials and workmanship for a period of 90 days from
the original purchase date and will replace same if found to be
defective and reported in writing to PSW within this period. The
fitness of the FlexList toolkit for any particular application is
not implied nor guaranteed. All other liabilities which may be
construed are specifically disclaimed except where required by
law.
Registration
Please fill out and return the registration post card. Print
your name, address, serial number, date and place of purchase.
Notices of updates and new example diskettes are mailed from the
registration roster. Thank you!
Acknowledgments
I wish to thank those FlexList customers that have contributed to
the present form of FlexList, Bruce Vantassel, President of
Intellisys Corporation, Miami, Florida, for his suggestions and
advice on adding sorting and searching functions and advice on
revising this manual and to Milton Palmer, Senior Scientist of
Ramsearch Company, College Park, Maryland, for his suggestions
and advice on more efficient sorting and searching by placing the
compare function pointer inside the FlexList header, and his
advice on more efficient copying operations, and specifically his
suggestion on making the find functions a combination of linear
and binary searches.
Thanks also to all you early FlexList customers, who believed in
parameterized list primitives even before OOP became a buzz word;
you have kept FlexList alive these first six years: from its
first inception and implementation in Turbo Pascal 2.0.
Special thanks to my mother for her patience in letting me use
her home to start PSW and listening to me go on hour after hour
about how useful FlexList would be to overworked programmers.
Lastly I wish to thank my Lord and Savior, Jesus Christ, who give
himself for me, that I might live.
Contents
Introduction
Chapter 1. Getting Started . . . . . . . . . . . . . . . . .9
Chapter 2. Programming with FlexList . . . . . . . . . . . 11
Chapter 3. FlexList Reference. . . . . . . . . . . . . . . 29
Appendix A. Common Mistakes . . . . . . . . . . . . . . . .107
Appendix B. Inside FlexList . . . . . . . . . . . . . . . .109
Appendix C. FlexList Source Code. . . . . . . . . . . . . .113
Index
Introduction
Anytime your C application requires a stack, queue, or linked
list, simply include flexlist.h in your source code and then
start defining your stack, queue, and/or list variables as type
FlexList. A FlexList can be initialized, by various constructor
functions, to store any type of data and then accessed as a
stack, queue, list, or even an array interchangeably!
With more than 30 FlexList functions to choose from, you can
push, pop, insert, delete, sort, store, recall, or find, to name
but a few. Access your data by value (copy) or by reference
(pointer). Or move nodes directly between FlexLists. Because
FlexList functions adjust automatically to different types of
data, new sets of primitives needn't be derived to accommodate
new data types. Thus your application's coding time and code
size won't continue to grow when you add new types of FlexLists.
A FlexList can even be made to accommodate heterogeneous data via
its virtual function hooks.
With FlexList you can quickly construct lists of lists or other
composite structures. And since FlexLists are initialized at run
time, the data they hold or even their creation can be specified
at run time thus allowing your application new dimensions of
adaptability to user inputs.
Use FlexList to code your next application's linked lists in
minutes instead of days, without the usual debugging and
documenting headaches associated with custom coding various list
types. It's no problem modifying your application in midstream
to incorporate various and differing list types; with FlexList no
linked list code needs to be scrapped or rewritten. The code
space you'll save over cloning list primitives for different data
types may just save you from having to go the overlay/swapping
route.
Chapter 1. Getting Started
The distribution diskette contains the source code for FlexList:
flexlist.h // ANSI C version
flexlist.c
flexlist.hkr // K&R version
flexlist.ckr
Copy these to the appropriate directories for the C compiler and
operating system you are using. You may need to rename these
files to suit your compiler.
For those of you who don't have smart linker/librarians on your
system, I've broken down the FlexList functions into individual
files and placed them into the following subdirectories:
flansic.src
flkrc.src
You will find makefiles in each subdirectory. Edit the macros in
the makefile to suit your environment. A FlexList library can be
quickly built for your compiler using the makefile.
Be sure to read the readme.doc file on the distribution diskette
for the latest revision information.
Note: FlexList is also available for C++.
Chapter 2. Programming with FlexList
This chapter is a combination of a brief tutorial on using the
FlexList tool and a logical survey of the FlexList functions.
You may find it useful to lookup the FlexList functions in the
reference chapter while reading the example programs here. Don't
worry too much about the details for now. Instead you should
finish this chapter with
1) an idea of the points to remember when programming with
FlexList,
2) a conceptual model of FlexList's hybrid stack-queue-list-
array data structure, and
3) an appreciation for the various ways that a FlexList can be
manipulated and accessed, namely: by value, by reference, or
by node.
After programming for a while with FlexList, be sure to reread
this chapter.
Let's first cover several points that you should keep in mind
when using FlexList in any application.
1. Include flexlist.h in any application using FlexList.
#include <flexlist.h>
2. Define your stack, queue, or list as a FlexList.
FlexList intStack;
3. Before using your FlexList you must call a constructor
function to initialize it for the size of the data that you
will be storing in it.
FLfixed(&intStack,sizeof(int));
4. The address of your FlexList must be passed as the first
parameter to FlexList functions. Where data copying is
involved, the address of the data is passed as the second
parameter. Remember, don't pass the data by value.
for (i = 1; i < 11; i++)
FLpushD(&intStack,&i); /* address of i */
5. FlexList functions return pointers or integers. A returned
value of zero indicates failure of the function to carry out
its task.
while (FLpopD(&intStack,&i)) /* loop until false */
printf("\n %d",i);
6. After you are finished with your FlexList you should call a
FlexList destructor function. In our example it isn't
really necessary since we've popped all the nodes anyway.
Let's include it though for completeness.
FLclear(&intStack);
7. Don't forget to link your application with the object module
created by compiling flexlist.c or with the library you
build.
Let's see the whole program.
#include <stdio.h> /* printf() */
#include <flexlist.h>
main() /* Count backwards from ten via a stack. */
{
FlexList intStack;
int i;
(void) FLfixed(&intStack,sizeof(int));
for (i = 1; i < 11; i++)
(void) FLpushD(&intStack,&i);
while (FLpopD(&intStack,&i))
(void) printf("\n %d",i);
(void) FLclear(&intStack);
return 0;
}
Dynamic FlexList Constructors
Let's continue with a survey of FlexList's various functions.
The FlexList tool has several constructor/destructor functions.
Why? Well the FlexList that we just used in the previous example
is a local variable. Actually only the FlexList header is a
local variable - the nodes in a FlexList are almost always
dynamically allocated! Suppose that we want the FlexList
variable itself to be dynamically allocated? Then we would use
the constructor function FLfixedNew.
Let's see that program again.
#include <stdio.h> /* printf() */
#include <flexlist.h>
main() /* Count backwards from ten via a stack. */
{
FlexL intS;
int i;
if ((intS = FLfixedNew(sizeof(int),0,FLDdestruct0))
== FlexL0) return 1;
for (i = 1; i < 11; i++)
(void) FLpushD(intS,&i);
while (FLpopD(intS,&i))
(void) printf("\n %d",i);
(void) FLdelete(&intS);
return 0;
}
Notice that the integer stack is now defined as type FlexL
instead of FlexList. FlexL is a pointer to a FlexList. I
contracted intStack to intS also as a reminder that it is a
pointer to a FlexList and not a FlexList. The constructor
function FLfixedNew returns a pointer to the FlexList it
allocates and initializes, otherwise it returns 0 or more
specifically (FlexL) 0. I've contracted all NULL constants and
defined them in flexlist.h, e.g. (FlexL) 0 is FlexL0. Several
additional parameters are also required by FLfixedNew but don't
worry about that now. Please note that FlexList primitives take
a FlexList pointer as their first parameter, with the exception
of FLdelete. That's why I didn't use the address of operator,
"&", with "intS" in this version like I did with "&intStack" in
the first.
The point of the two previous examples is that FlexList
constructor/destructor functions come in two varieties: those
that construct/destruct FlexList variables defined at compile
time, i.e. local, static, and global variables, versus their
counter parts that construct/destruct FlexList variables
dynamically allocated at run time.
FlexList Constructor/Destructor Functions
1. Constructor/destructor functions for FlexLists defined at
compile time:
FLfixed() FLunpack() FLvariant()
FLstr() FLclear()
2. Constructor/destructor functions for FlexLists allocated at
run time:
FLfixedNew() FLunpackNew() FLvariantNew()
FLstrNew() FLdelete()
The FLunpack and FLunpackNew functions are used to explode C
arrays (vectors) into FlexLists. Each FlexNode holds one cell of
the array (see section on compaction functions). FLvariant and
FLvariantNew construct FlexLists that have variant sized
FlexNodes (see FLvariant in reference chapter to see how to
construct heterogeneous FlexLists)! FLstr and FLstrNew are
actually macros that call FLvariant and FLvariantNew
respectively, constructing FlexLists that contain FlexNodes just
big be enough to hold C strings within. FLclear deallocates all
FlexNodes in a FlexList, while FLdelete calls FLclear and then
proceeds to deallocate the dynamically allocated FlexList
variable (header).
FlexList Header Access Functions
As you become more familiar with what's inside a FlexList you
will want to access the data fields inside the FlexList header.
Never access these fields directly! There is little performance
penalty since most of these functions are in fact macros. You
should decide right now that you are only going to access the
guts of a FlexList via FlexList functions. This insures the
integrity of the FlexList by imposing the OOP (Object Oriented
Programming) concept of encapsulation. The C language doesn't
enforce access restriction as does the C++ language, so you're on
the honor system!
FLfrontD() FLcurrentD() FLrearD()
FLcurNum() FLnodes() FLmaxNodes()
FLsetMaxNodes() FLnotFull() FLsizeofNodeData()
FLisSorted() FLunSort() FLcompare()
FLsetCompare() FLisFixed() FLisVariant()
FLData()
A FlexList can be accessed as a stack, queue, list, or even an
array once it has nodes in it, interchangeably. The FlexList
header keeps track of everything so if your pushing data onto
your "stack" at one moment, you can recall an element from your
"array" the next. You can sort your FlexList, then perform
various other operations on it and FLisSorted will tell you if it
is still sorted. You can set an upper limit on the number of
nodes a FlexList is allowed to hold with FLsetMaxNodes. You will
come to know what each function does with time.
FlexList Stack and Queue Functions
A stack provides LIFO (Last In, First Out) storage. A complete
set of stack primitives is provided. These functions don't
disturb the queue, list, or array structure of a FlexList. In
other words, you can access your FlexList as a stack at any time
and revert back to accessing it as a queue, list, or array
freely.
FLpushN() FLpushD() FLpopN()
FLpopD() FLtopD() FLinsQN()
FLinsQD() FLfrontD() FLrearD()
A queue provides FIFO (First In, First Out) storage. Notice that
some of the stack functions double up here as queue functions,
e.g. FLpopD, FLtopD. Also I have again included some of the
FlexList header access functions, i.e. FLfrontD and FLrearD which
return pointers to the data in the first and last nodes
respectively. Basically I'm suggesting various logical ways to
categorize FlexList functions to help you remember them. You'll
find that several functions may belong in multiple categories.
The functions ending with "N" work directly with the FlexNodes
which contain your data. For an example, suppose that you want
to pop your stack directly into your queue. The following code
shows how.
#include <stdio.h> /* printf() */
#include <flexlist.h>
FlexList s, q;
int a[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int *iptr;
#define inT0 ((int *)0)
main() /* count to ten the hard way */
{
(void) FLunpack(&s,sizeof(a[0]),sizeof(a)/
sizeof(a[0]),a);
(void) FLfixed(&q,FLsizeofNodeData(&s));
while ((iptr = FLinsQN(&q,FLpopN(&s))) != inT0)
(void) printf("\n %d",*iptr);
(void) FLclear(&s);
(void) FLclear(&q);
return 0;
}
In this example the stack is constructed by "exploding" an array
of integers into a FlexList. Next the queue is constructed to
hold the same size data as the stack. Then the stack is popped
directly into the queue and a pointer to the data in the newly
inserted queue node is captured and tested to control the
looping! I print the integer each time so you can see that it
made it into the queue. Did you notice how I defined the NULL
integer pointer? I did that here so you'll know what's going on
when you see other NULL pointers elsewhere.
FlexList List Functions
Any FlexList can be treated as a doubly linked list thereby
providing sequential storage. You can insert nodes or delete
them. The FlexList header maintains a current node pointer that
lets the list functions know where the insertion or deletion is
to take place. Stack and queue functions don't disturb this
current pointer unless of course it points to the top/front of
the stack/queue and that node is popped/removed. In that case
the current node becomes undefined.
FLmkcur() FLinsN() FLinsD()
FLinsSortN() FLinsSortD() FLdelN()
FLdelD() FLnextD() FLprevD()
FLcurNum() FLcurrentD() FLcompare()
FLsetCompare()
FlexList nodes are numbered starting at one. When FLnextD
reaches the end of the list the current node number is set to
zero which is said to be undefined and FLnextD returns the NULL
void pointer. On the next call to FLnextD the current node
becomes one, that is of course if there are nodes in the
FlexList! FLprevD works the same way. This mechanism makes it
handy to walk around lists pausing at the ends. If you want to
set the current pointer to a particular node, use FLmkcur.
Oh, I guess I should mention again that you can store any type of
data in a FlexList not just integers. Let's see something like
that last example again with strings.
#include <stdio.h> /* printf() */
#include <flexlist.h>
FlexList l;
char *a[] = { "Now is the time", "for all good",
"programmers to cut", "their coding time",
"with FlexList!"
};
char **sptr;
#define chaRR0 ((char **)0)
main() /* PSW propaganda */
{
(void) FLunpack(&l,sizeof(a[0]),sizeof(a)/
sizeof(a[0]),a);
while ((sptr = FLnextD(&l,(void *)0)) != chaRR0)
(void) printf("\n %s",*sptr);
(void) FLmkcur(&l,FLnodes(&l));
while (FLdelD(&l,(void *)0))
/* null statement */; /* FLclear(&l); */
(void) printf("\n There should be zero nodes now: %d",
FLnodes(&l));
return 0;
}
In this program I exploded a vector of char pointers into a
FlexList. Whenever FlexLists are constructed the current node is
set as undefined so FLnextD starts walking across the FlexList
beginning with the first node. FLnextD will copy the data in the
next node to whatever address you specify in the second parameter
unless of course it is the NULL address! When you are browsing
the reference chapter you will notice many FlexList functions
that copy data to/from a FlexNode when an address is given. If
the NULL address is specified the copying action is inhibited but
the function otherwise performs its purpose. In this exampleFLnextD is inhibited from copying any data but it never the less
moves the current pointer on to the next node. FLnextD also
returns a void pointer to the data in the next node. I capture
that pointer in order to print the string but I'm also using it
to control the loop.
All FlexList functions return either pointers or integer types
that are non zero only when the respective function completes
successfully. The void pointers returned from FlexList functions
point to the user data in focus. In the case of FLnextD it
points to the user data in the next node. I have simply type
casted this pointer to a pointer to the type of data I'm storing
in the FlexNodes in order to gain access to that data. As you
can see FlexList functions allow you to access you data by value
(copy) or by reference (pointer) as well as moving nodes directly
between/within FlexLists.
Back to our example, FLmkcur moves the current node pointer to
the last node in the list. FLmkcur also returns a pointer to the
data in the last node but I choose to ignore it. Now FLdelD is
used to delete the nodes from the list. FLdelD removes the
current node after copying its contents to the address specified
(copying is inhibited here by the NULL address) and then unlinks
the FlexNode from the FlexList and proceeds to deallocate it
making the previous node in the FlexList the new current node. I
might add that FLinsD does the exact opposite, i.e. inserts a new
FlexNode after the current node making the new node current.
Again the stack and queue structure of FlexList is undisturbed by
any list functions invoked on the FlexList and vice versa.
FlexList Search/Sort Functions
The Search/Sort functions allow you to lookup and/or sort your
data. Every FlexList has a user definable compare function. Use
FLsetCompare to set a FlexList's internal compare function
pointer. To facilitate sorting define your compare function to
return -1, 0, or 1 to indicate whether the first data being
compared is less than, equal to, or greater than the second,
respectively. The compare function is also used for matching in
the FLfind...() functions. Please note that most of the
functions mentioned here modify the current node setting, thus
they interact with the list functions mentioned earlier.
FLinsSortN() FLinsSortD() FLfindFirstD()
FLfindNextD() FLfindLastD() FLfindPrevD()
FLsort() FLisSorted() FLunSort()
FLcompare() FLsetCompare()
Use FLinsSortD/N() to perform insertion sorts. If the list isn't
sorted then FLsort will be called automatically before attempting
the insertion. If a compare function pointer hasn't been setup
then the insertion is aborted.
The FLfind...D functions work regardless if the FlexList is
sorted or not. If it is sorted then the binary search algorithm
is used to find the first/last matching data and a linear search
is used to find the next/previous match stopping immediately
after the first mismatch. If the FlexList is not sorted then the
linear search algorithm is used to find the first/last matching
data and again to find the next/previous match stopping only at
the ends of the list.
Use FLsort or FLsetCompare to setup the compare function pointer.
If the NULL compare function pointer, FLcompare0 (defined in
flexlist.h), is passed to FLsort then the previous compare
function pointer is used to sort the list. Call FLisSorted to
determine whether a FlexList is still sorted from its last sort.
For example, suppose you sort a list and pop some nodes off the
front. Well that won't cause the FlexList to be unsorted so
FLisSorted will return true. But if you push some data onto it
treating it like a stack, that may or may not ruin the sorted
order. FLisSorted will return false because it can no longer
guarantee that the FlexList is sorted. You need to be careful
though since FLnextD, FLprevD, and FLmkcur won't cause FLisSorted
to reset to false even though you might have modified the data in
the FlexNode via the returned void pointer! In that case you may
want to call FLunSort to reset FLisSorted so that it will return
false.
The following example performs an unsorted linear search followed
by an alphabetical sort.
#include <stdio.h> /* printf() */
#include <string.h> /* strstr(), strcmp() */
#include <flexlist.h>
int strStr(char *s, char *t)
{
return !(int)strstr(s,t);
}
main()
{
FlexList l;
char *s, sbuf[80];
char *mask = "overtime";
int i;
(void) FLstr(&l);
(void) FLinsD(&l,"Once upon a time there were three");
(void) FLinsD(&l,"programmers, who worked");
(void) FLinsD(&l,"allot of overtime!");
(void) FLinsQD(&l,"That was before the FlexList Fox");
(void) FLinsQD(&l,"joined the staff!");
for ((void)FLmkcur(&l,0); FLnextD(&l,sbuf);
/* no reinit */)
(void) printf("\n Node: %d. %s",
FLcurNum(&l),sbuf);
(void) FLsetCompare(&l,FLcomparE(strStr));
if ((s = FLfindFirstD(&l,mask)) != (char *)0)
(void) printf("\n Mask: \"%s\" found in \
node: %d. %s",mask,FLcurNum(&l),s);
(void) FLsort(&l,FLcomparE(strcmp));
for (i = 1; FLrecallD(&l,sbuf,(unsigned)i); i++)
(void) printf("\n Node: %d. %s",
FLcurNum(&l),sbuf);
(void) FLclear(&l);
return 0;
}
This program constructs a variant FlexList via the macro
constructor FLstr which expands into a call to FLvariant. The
FlexNodes in this FlexList are only be enough to hold the
character strings passed as parameters (please note that
character string constants are pointers to the strings so I
didn't use the address of, "&", operator!) I didn't use the
FLunpack constructor because it builds fixed size FlexNode
(homogeneous) FlexLists - an array has fixed cell sizes. Instead
I inserted the strings one by one and queued the last two just to
be different.
The first "for loop" uses FLnextD to verify the contains of the
FlexNodes. FLnextD only copies the string and zero terminator
thanks to the virtual function table's function pointers (see
FLvariant in the reference chapter to see how to construct
heterogenous lists). Be sure that the variable whose address you
pass to FLnextD is big enough to accommodate the largest data
that can be read! You should have noticed that I had to use
FLmkcur(&l,0) since the current node pointer is still pointing to
the last node inserted and not the last node queued. Remember,
queue functions don't disturb the list structure - the current
node concept is part of the list structure, not the queue
structure!
Since the list is not sorted, FLfindFirstD searches in a linear
fashion starting with the first node, internally calling the
compare function setup with FLsetCompare. The FLcomparE macro,
defined in flexlist.h, type casts strStr to the precise functionpointer type required by both FLsetCompare and FLsort. My strStr
returns 0 if t is within s. Since only a linear search will be
used with this compare function, it doesn't matter that is
doesn't return -1 or 1 to indicate less than or greater than.
The program proceeds with a standard alphabetical sort and the
resultant ordering is displayed with FLrecallD, an array access
function which you'll see in the next section.
FlexList Array Functions
An array provides randomly accessible storage. A FlexList can
also be accessed as an array once it has nodes in it.
FLstoreD() FLrecallD() FLmkcur()
FLcurrentD() FLcurNum()
The last node accessed becomes the new current node. When
randomly accessing a FlexList, FLmkcur is called internally by
both FLstoreD and FLrecallD to make the requested node current.
FLmkcur determines which pointer (front, current, or rear) is
closest to the requested node. It then follows the FlexList's
linkage from that closest pointer to the newly requested node.
The current pointer is left positioned at the new node. Please
note that array, search/sort, and list functions interact in that
they all work with and modify the current node setting. Stack
and queue functions are independent, however.
FlexList Compaction Functions
Sometimes you want to work with a list, other times it's more
convenient to work with an array. Although FlexList allows this
chameleon behavior, your application may progress in stages that
favor a linked list at one point and a conventional C array at
another. FlexList has "compaction" functions for converting a
conventional array into a FlexList or vice versa, thus allowing
you to optimize the performance of your application.
FLunpack() FLunpackNew()
FLpack() FLpackPtrs()
You can think of the FLunpack/FLunpackNew as exploding the
conventional C array into a FlexList. Think of the FLpack
function as doing the exact opposite or imploding a FlexList into
a conventional C array. Arrays compacted by FLpack and
FLpackPtrs must be explicitly deleted with a call to free when nolonger needed if their memory is ever to be recovered for
subsequent reuse. FLpackPtrs returns an array of void pointers
pointing to the data in the FlexNodes. This array is NULL
terminated to facilitate subsequent processing.
For the last example program we'll clone a vector of char
pointers but the clone will have the advantage over its parent of
being sorted in alphabetical order.
#include <stdio.h> /* printf() */
#include <stdlib.h> /* free() */
#include <string.h> /* strcmp() */
#include <flexlist.h>
char *a[] = { "one", "two", "three", "four", "five" };
char **A;
int strCmp(char **s, char **t)
{
return strcmp(*s,*t);
}
main()
{
FlexList l;
int i;
(void) FLunpack(&l,sizeof(a[0]),sizeof(a)/
sizeof(a[0]),a);
(void) FLsort(&l,FLcomparE(strCmp));
A = FLpack(&l);
for (i = 0; i < sizeof(a)/sizeof(a[0]); i++)
(void) printf("\n a[%d] = %s",i,a[i]);
if (A) {
for (i = 0; i < FLnodes(&l); i++)
(void) printf("\n A[%d] = %s",
i,((char **)A)[i]);
free(A);
}
(void) FLclear(&l);
return 0;
}
Remember that the FlexNodes in this program contain char pointers
and that the compare function is passed pointers to the char
pointers, that is why the strCmp has to dereference them.
Many commercial C toolbox functions require vector parameters.
With FlexList's compaction functions you can manipulate vectors
on the fly. The vectors can be stored in files and loaded as
needed via a FlexList and subsequent packing. The vector canthen be kept around only during the computation phase in which it
is needed. Large, oversized, static vectors need not be
allocated at compile time to cope with worst case scenarios,
thereby consuming precious data segment space within your
program.
Accessing FlexList Nodes and Data
Now that we've finished categorizing FlexList functions along the
lines of its hybrid stack-queue-list-array structure, let's
rethink what we've seen in terms of how the FlexList was
accessed, namely: by value, by reference, and by node. This
gives us a second way to analyze FlexList functions.
"By value" implies that the data is copied to or from a FlexNode.
For example, with FLpopD the top node of the stack is popped and
the data is copied to the address specified by the second
parameter before the node is freed and returned to the heap. We
are in effect accessing the data in the top node by value since
we are retrieving, in actuality, a copy of it.
FLpopD(&s,&i); /* i is same type in FlexNode */
"By reference" implies that the data in the FlexNode is accessed
by pointer. You will need to type cast these void pointers to
pointers to the type of data you have stored in the FlexNodes.
Suppose we're walking backward across a FlexList of integers with
the code:
while ((iptr = FLprevD(&l,(void *)0)) != (int *)0)
(void) printf("\n %d",*iptr);
All void pointers returned by FlexList functions point to user
data. Thus the data can be modified directly. "By reference"
functions are provided to speed up processing. Without pointer
access you would have to first copy the data out of the FlexNode,
modify it and then copy it back. With large data structures that
could prove to be quite inefficient. Please note the FLnextD and
FLprevD are purely "by reference" when called with their second
parameters equal to the NULL address. Actually all FlexList
functions returning void pointers allow access "by reference" in
combination perhaps with "by value" access.
In queuing network simulations you will want to move nodes
between FlexLists rapidly. Without access "by node" you would
have to "FLpopD" the source queue and "FLinsQD" the destination
queue. This would entail copying the data from the front node
into a local variable of the same type, unlinking and
deallocating the FlexNode, then reallocating a new FlexNode and
linking it into the other queue and finally copying the data from
the local variable back into the node. The faster way is tounlink the FlexNode from the source queue and relink it directly
into the destination queue, e.g.
FLinsN(&dstQ,FLpopN(&srcQ));
If dstQ is already full then the node popped from srcQ is lost in
the twilight zone. A better approach would be to prevent the
chance of FlexNodes being left dangling:
while (FLnotFull(&dstQ) && FLnodes(&srcQ))
(void) FLinsN(&dstQ,FLpopN(&srcQ));
The "By node" functions unlink and relink FlexNodes directly
between compatible FlexLists. Compatible in this sense means
that both FlexLists have equal sizeofNodeData fields (not
necessarily initialized for the same data type) . Use the
FLsizeofNodeData function to read the sizeofNodeData field. Two
FlexLists could also be considered to be compatible if they are
both variant FlexLists with compatible data. I should point out
that variant FlexLists have the sizeofNodeData fields set to
zero. Be careful not to assume that two FlexLists are compatible
just because both sizeofNodeData fields are equal to zero. You
can use FLisVariant to retrieve the virtual function table
pointer within the FlexList header. If two variant FlexLists use
the same virtual function table, they are most likely compatible.
You are responsible for insuring that your FlexLists are
compatible. Remember also, FlexNodes unlinked with a function
ending with "N" must be relinked with a function ending with "N"
to a compatible FlexList or otherwise explicitly disposed of.
Summary
Let's review what we learned starting with the points to remember
when programming with the FlexList tool.
1. Be sure to include the FlexList header in any module
that references FlexList functions.
2. Define your global, static, and local stacks, queues,
lists, etc. as "FlexList". Define your dynamic
versions as pointers to FlexLists, i.e. "FlexL".
3. Construct your FlexList variable with a static
constructor function and your FlexList pointer with a
dynamic constructor function.
4. The first parameter of all FlexList functions, with the
exception of FLdelete, is an address of a FlexList, or
putting it another way, is a pointer to a FlexList. If
the function is somehow involved with the copying of
user data, the address of the data is always passed in
the second parameter.
5. All FlexList functions return either pointers or
integers. A returned value of zero indicates failure
of the function to complete its task.
6. Destruct all FlexLists when they are no longer needed.
Use FLclear on global, static, or local FlexList
variables and FLdelete on dynamic FlexLists.
7. Link your application with the compiled flexlist object
module or the flexlist library you build.
Next, let's review the various functions available in the
FlexList tool. FlexList functions can be categorized according
to the logical nature of a FlexList's inherent hybrid stack-
queue-list-array structure.
FlexList Constructor/Destructor Functions
FLfixed() FLunpack() FLvariant()
FLstr() FLclear()
FLfixedNew() FLunpackNew() FLvariantNew()
FLstrNew() FLdelete()
FlexList Header Access Functions
FLfrontD() FLcurrentD() FLrearD()
FLcurNum() FLnodes() FLmaxNodes()
FLsetMaxNodes() FLnotFull() FLsizeofNodeData()
FLisSorted() FLunSort() FLcompare()
FLsetCompare() FLisFixed() FLisVariant()
FLData()
FlexList Stack and Queue Functions
FLpushN() FLpushD() FLpopN()
FLpopD() FLtopD() FLinsQN()
FLinsQD() FLfrontD() FLrearD()
FlexList List Functions
FLmkcur() FLinsN() FLinsD()
FLinsSortN() FLinsSortD() FLdelN()
FLdelD() FLnextD() FLprevD()
FLcurNum() FLcurrentD() FLcompare()
FLsetCompare()
FlexList Search/Sort Functions
FLinsSortN() FLinsSortD() FLfindFirstD()
FLfindNextD() FLfindLastD() FLfindPrevD()
FLsort() FLisSorted() FLunSort()
FLcompare() FLsetCompare()
FlexList Array Functions
FLstoreD() FLrecallD() FLmkcur()
FLcurrentD() FLcurNum()
FlexList Compaction Functions
FLunpack() FLunpackNew() FLpack()
FLpackPtrs()
Finally, FlexLists can be accessed "by value", "by reference",
and "by node." "By value" entails the copying of user data
between the FlexNodes and user specified addresses. If the
address specified is NULL than the copying of data is inhibited
but the function performs otherwise as expected. The address is
always the second parameter of the FlexList function requiring
it. "By reference" infers that user data is manipulated directly
inside a FlexNode via a pointer. All FlexList functions
returning void pointers allow "by reference" access. "By node"
functions allow FlexNodes to be yanked/inserted from/into
FlexLists. These functions are named with "N" suffixes. Move
FlexNodes only between compatible FlexLists. Don't leave
FlexNodes dangling: either insert them back into a compatible
FlexList with an "N" function or explicitly free them.
By now you should be ready to start the planning and subsequent
coding of your FlexList application with the help of the
reference chapter on FlexList functions. Later, when you feel
comfortable with FlexList, you will want to try your hand at
deriving your own variant FlexLists (lists that containheterogeneous data). Be sure to read the entry for FLvariant in
the reference chapter for an explanation of writing your own
FlexList virtual functions that accommodate your heterogeneous
data. The FlexList dynamic constructor entries, i.e. constructor
functions ending with "New", explain how to encapsulate your
list-pertinent data within FlexList headers.
Chapter 3. FlexList Reference
This chapter contains a detailed specification of each FlexList
function.
FLclear Static Destructor
* Summary
#include <flexlist.h>
int FLclear(FlexL L);
* Description
FLclear deletes all nodes in the FlexList. With
variant FlexLists all nodes may not be able to be
destructed.
* Return value
FLclear returns zero if any nodes are left remaining or
if "L" is NULL, otherwise it returns 1.
* See Also
FLdelete
* Example
#include <stdio.h> /* printf() */
#include <flexlist.h>
int i[] = { 1, 2, 3, 4, 5 };
main()
{
FlexList l;
(void) FLunpack( &l, sizeof(i[0]), sizeof(i) /
sizeof(i[0]),i);
(void) printf("\n nodes: %d",FLnodes(&l));
(void) FLclear(&l);
(void) printf("\n nodes: %d",FLnodes(&l));
return 0;
}
FLcompare Header Access
* Summary
#include <flexlist.h>
int (*FLcompare(FlexL L))
(const void *D1, const void *D2);
* Return value
The FLcompare macro returns the pointer to the user
defined compare function used in searches and sorts.
* Remarks
If you are sorting a FlexList on various keys at
different times, it is convenient to know if the
FlexList is sorted and on what key. Use FLisSorted and
FLcompare to determine this.
* See also
FLsetCompare, FLsort, FLisSorted, FLunSort
* Example
#include <stdio.h> /* printf() */
#include <flexlist.h>
int a[] = { 1, 2, 3, 4, 5 };
int intAscending(int *i1, int *i2)
{ return ((*i1 < *i2)? -1 : (*i1 > *i2)? 1 : 0); }
int intDescending(int *i1, int *i2)
{ return ((*i1 < *i2)? 1 : (*i1 > *i2)? -1 : 0); }
FLcompare
void countToFive(FlexL L)
{
if (FLcompare(L) == FLcomparE(intDescending))
for (FLmkcur(L,0);FLprevD(L,(void *)0);
/* no reinit */)
printf("\n%d",*(int *)FLcurrentD(L));
else
for (FLmkcur(L,0);FLnextD(L,(void *)0);
/* no reinit */)
printf("\n%d",*(int *)FLcurrentD(L));
}
main()
{
FlexList l;
FLunpack(&l,sizeof(a[0]),sizeof(a)/
sizeof(a[0]),a);
FLsort(&l,FLcomparE(intDescending));
countToFive(&l);
FLsort(&l,FLcomparE(intAscending));
countToFive(&l);
FLclear(&l);
return 0;
}
This program always prints the contents of the FlexList
in ascending order by determining the sorted order and
then either walking backward or forward across the
FlexList to achieve an ascending order.
The FLcomparE macro, defined in flexlist.h, is used to
precisely type cast my compare function to the type
required by FLsort and FLsetCompare.
FLcurNum Header & List Access
* Summary
#include <flexlist.h>
unsigned FLcurNum(FlexL L);
* Return Value
The FLcurNum macro returns the number of the current
node in the FlexList. If there is no current node set
or "L" is NULL then zero is returned.
* Remarks
FlexNodes are numbered starting with one. Whenever a
FlexList is first constructed or cleared the current
node is set to zero.
* See Also
FLcurrentD, FLmkcur
* Example
#include <flexlist.h>
main()
{
FlexList l;
FLstr(&l); /* FLcurNum(&l) == 0 */
FLinsD(&l,"one");
FLinsD(&l,"two");
FLinsQD(&l,"three"); /* FLcurNum(&l) == 2 */
FLdelD(&l,(void *)0); /* FLcurNum(&l) == 1 */
/* list now contains: "one", "three" */
FLmkcur(&l,FLnodes(&l)); /* FLcurNum(&l) == 2 */
FLclear(&l); /* FLcurNum(&l) == 0 */
return 0;
}
FLcurrentD Header & List Access
* Summary
#include <flexlist.h>
void * FLcurrentD(FlexL L);
* Return Value
The FLcurrentD macro returns a pointer to the data area
of the current node or NULL if there is no current
node.
* See Also
FLfrontD, FLrearD, FLmkcur, FLnextD, FLprevD
* Example
#include <stdio.h> /* printf() */
#include <flexlist.h>
main() /* count to three */
{
FlexList l;
FLstr(&l);
FLinsQD(&l,"one");
FLinsQD(&l,"two");
FLinsQD(&l,"three");
while (FLnextD(&l,(void *)0))
printf("\n%s",(char *)FLcurrentD(&l));
FLclear(&l);
}
The current node remains set at zero until the "while
loop." FLcurrentD returns a pointer to each successive
string until FLnextD reaches the end of the FlexList.
FLData Header Access
* Summary
#include <flexlist.h>
void * FLData(FlexL L);
* Return value
The FLData macro returns a pointer to the beginning of
the user data area within the FlexList. The FlexList
must have been constructed with FLfixedNew,
FLunpackNew, FLvariantNew, or FLstrNew. In other words
it must be a dynamically allocated FlexList. If L is
NULL or it was not dynamically allocated then NULL is
returned.
* Remarks
If your dynamic FlexList doesn't store data in the
FlexList header, don't use the returned pointer to
access data that isn't there. In any case the pointer
can be interpreted as a boolean value with true
indicating that the FlexList was dynamically allocated.
A Flexlist doesn't maintain a sizeofLocalData field
from which it can ascertain whether or not you store
any data in the FlexList header. Therefore FLData
can't tell whether or not the header has been enlarged
to accommodate your data. It knows only that
dynamically allocated headers can be enlarged to
accommodate user data and static ones can't! It simply
returns a pointer to the end of usual FlexList data and
the start of your data if any. Leaving out a
sizeofLocalData field in the header was a design trade
off to save space.
* See also
FLfixedNew, FLunpackNew, FLvariantNew
* Example
The FLfixedNew entry has an excellent example of using
FLData to initialize and modify user data local to a
FlexList.
FLdelD List Access
* Summary
#include <flexlist.h>
int FLdelD(FlexL L, void *D);
* Description
Copies data from current node to specified location,
i.e. "void *D", if any then deletes the current node
making the previous node current.
* Return Value
Returns 1 if successful in deleting the current node,
otherwise 0 is returned to indicate failure.
* See Also
FLdelN, FLinsD, FLinsN, FLpopD, FLpopN
* Example
#include <stdio.h> /* printf() */
#include <flexlist.h>
int a[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
main() /* count down from ten */
{
FlexList l;
int i;
FLunpack(&l,sizeof(a[0]),sizeof(a)/
sizeof(a[0]),a);
FLmkcur(&l,FLnodes(&l));
while (FLdelD(&l,&i))
printf("\n%d",i);
return 0;
}
The program initializes a FlexList with an array of ten
integers. The last node in the list is made the
current node. Finally, the nodes are deleted from the
rear towards the front and the contents of each node is
displayed.
FLdelete Dynamic Destructor
* Summary
#include <flexlist.h>
int FLdelete(FlexL *Lptr);
* Description
Call FLdelete to destruct dynamically allocated
FlexLists, i.e. those constructed by FLfixedNew,
FLunpackNew, FLvariantNew, or FLstrNew. FLdelete first
calls the user specified FLDdestruct virtual function
with the address of user's data in the FlexList header.
If the FLDdestruct function returns true then FLclear
is called to destruct the FlexNodes. If all FlexNodes
are successfully destructed then the FlexList is freed
and true returned.
* Return value
Returns non zero if the FlexList is deallocated.
* Remarks
FLdelete checks to see if the FlexList was dynamically
allocated before proceeding. If the FlexList is
dynamically allocated the FLDdestruct pointer in the
FlexList header will be something other than NULL. If
you need to determine if a FlexList was dynamically
allocated call FLData; it returns true whenever the
FlexList is dynamic.
* See Also
FLfixedNew, FLvariantNew, FLData, FLclear
* Example
See the example for the FLfixedNew entry.
FLdelN List Access
* Summary
#include <flexlist.h>
FlexN FLdelN(FlexL L);
* Description
Deletes the current node from the list, if any, by
unlinking it and returning a pointer to it. The
previous node becomes the new current node. If there
is no previous node then the current node becomes
undefined and curNum is 0.
* Return Value
FLdelN returns a pointer to the unlinked node or NULL
if there is no current node to unlink. Any unlinked
node must be relinked into a FlexList with a FlexList
function ending with "N" or otherwise explicitly freed!
* See Also
FLpopN, FLinsN, FLdelD, FLpushN, FLinsQN, FLinsSortN
* Example
#include <stdio.h> /* printf() */
#include <flexlist.h>
int ints[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
main() /* count down from ten */
{
FlexList src, dst;
FLunpack(&src,sizeof(int),sizeof(ints)/
sizeof(int),ints);
FLfixed(&dst,sizeof(int));
FLmkcur(&src,FLnodes(&src));
while (FLnotFull(&dst) && FLnodes(&src))
FLinsN(&dst,FLdelN(&src));
while (FLpopD(&dst,ints))
printf("\n%d",ints[0]);
return 0;
}
FLfindFirstD List Access
FLfindLastD
FLfindNextD
FLfindPrevD
* Summary
#include <flexlist.h>
void * FLfindFirstD (FlexL L, const void *D);
void * FLfindLastD (FlexL L, const void *D);
void * FLfindNextD (FlexL L, const void *D);
void * FLfindPrevD (FlexL L, const void *D);
* Description
The FLfind...D functions work regardless if the
FlexList is sorted or not. If it is sorted then the
binary search algorithm is used to find the First/Last
matching data and a linear search is used to find the
Next/Prev match stopping immediately after the first
mismatch. If the FlexList is not sorted then the
linear search algorithm is used to find the First/Last
matching data and again to find the Next/Prev match
stopping only at the ends of the list.
* Return Value
FLfind...D returns a pointer to the data in the
FlexNode found to be a match. If no match is found
NULL is returned.
* See Also
FLsort, FLinsSortD, FLsetCompare
* Example
The example program first searches an unsorted list of
integers. The list is sorted and searched again. Both
forward and backward searches are employed.
#include <stdio.h> /* printf() */
#include <stdlib.h> /* abs() */
#include <flexlist.h>
#define MatchTolerance 5
int ints[] = { 40, 70, 23, 5, 67, 2 ,10,
1 , 5, 3, 36, 27 };
FLfindFirstD
FLfindLastD
FLfindNextD
FLfindPrevD
int intcmp(int *i1, int *i2)
{ return (*i1 - *i2); }
int intmatch(int *i1, int *i2)
{
if (abs(*i1 - *i2) < MatchTolerance)
return 0;
return 1;
}
void search(FlexL L)
{
int i;
FLsetCompare(L,FLcomparE(intmatch));
for (i = 1; i <= 100; i += MatchTolerance) {
printf("\n\nsearch forward for %d +/-%d.\n",
i, MatchTolerance);
if (FLfindFirstD(L,&i))
printf("\nnode: %3d value: %3d",
FLcurNum(L),*(int *)FLcurrentD(L));
while (FLfindNextD(L,&i))
printf("\nnode: %3d value: %3d",
FLcurNum(L),*(int *)FLcurrentD(L));
printf("\n\nsearch backward for %d"
" +/- %d.\n",i,MatchTolerance);
if (FLfindLastD(L,&i))
printf("\nnode: %3d value: %3d",
FLcurNum(L),*(int *)FLcurrentD(L));
while (FLfindPrevD(L,&i))
printf("\nnode: %3d value: %3d",
FLcurNum(L),*(int *)FLcurrentD(L));
}
}
FLfindFirstD
FLfindLastD
FLfindNextD
FLfindPrevD
main()
{
FlexList l;
FLunpack(&l,sizeof(int),sizeof(ints)/
sizeof(int),ints);
search(&l);
FLsort(&l,FLcomparE(intcmp));
search(&l);
FLclear(&l);
return 0;
}
The FLcomparE macro, defined in flexlist.h, is used to
precisely type cast my two compare function pointers,
intmatch and intcmp, to the types required by
FLsetCompare and FLsort respectively.
FLfixed Static Constructor
* Summary
#include <flexlist.h>
FlexL FLfixed(FlexL L, size_t sizeofNodeData);
* Description
FLfixed initializes the FlexList pointed to by L to
hold data the size of sizeofNodeData. MaxNodes is set
to FLmaxMaxNodes, the maximum allowed for any FlexList
which is UINT_MAX (the largest value of an unsigned
integer).
The FlexList can subsequently be used to warehouse data
of this size.
* Return value
If successful, FLfixed returns L otherwise it returns
FlexL0 which is defined in flexlist.h as (FlexL) 0.
* See Also
FLfixedNew, FLunpack, FLunpackNew, FLvariant,
FLvariantNew, FLstr, FLstrNew
* Example
#include <flexlist.h>
main() /* construct a list of floats */
{
FlexList l;
float f;
if (!FLfixed(&l,sizeof(f)))
return 1;
f = 3.5;
FLpushD(&l,&f);
...
}
FLfixedNew Dynamic Constructor
* Summary
#include <flexlist.h>
FlexL FLfixedNew(
size_t sizeofNodeData,
size_t sizeofLocalData,
int (*FLDdestruct)(void *LD)
);
* Description
FLfixedNew allocates and initializes a FlexList big
enough to hold user data within the FlexList header.
MaxNodes is set to FLmaxMaxNodes, the maximum allowed
for any FlexList which is UINT_MAX (the largest value
of an unsigned integer).
The FlexList can subsequently be used to warehouse data
in the FlexNode of the size sizeofNodeData. The
FlexList header can warehouse data of the size
sizeofLocalData.
Use FLdelete to destruct dynamically allocated
FlexLists. FLdelete calls the user defined function
FLDdestruct which is passed the address of user data in
the FlexList header (the address is never NULL). If
your FLDdestruct function returns something other than
zero, FLdelete will then call FLclear to destruct the
FlexNodes and if that is successful, FLdelete then
frees the dynamically allocated FlexList. If your
FLDdestruct function returns zero then FLdelete will
return zero.
* Return value
If successful, FLfixedNew returns a pointer to a
dynamically allocated FlexList, otherwise it returns
FlexL0 which is defined in flexlist.h as (FlexL) 0.
* Remarks
If your dynamic FlexList doesn't need to store data in
the FlexList header then pass zero to the
sizeofLocalData parameter.
FLfixedNew
If your application doesn't require a FLDdestruct
function call FLfixedNew with the NULL pointer
constant, FLDdestruct0, defined in flexlist.h.
If your dynamic FlexList doesn't store data in the
FlexList header, don't access data with FLData!
Likewise if you do specify a FLDdestruct function, be
sure your function ignores the local data parameter
passed to it! A Flexlist doesn't maintain a
sizeofLocalData field from which it can ascertain
whether or not you store any data in the FlexList
header. This was a design consideration to save space
in the header.
Use FLData and FLisFixed to determine if a FlexList was
constructed with FLfixedNew or FLunpackNew. FLData
returns true for dynamically allocated FlexLists.
* See Also
FLData, FLdelete, FLisFixed, FLfixed, FLunpack,
FLvariant
* Example
This program builds a list of floats and then aliases
it. When FLdelete is called it won't destruct the
FlexList until all references to it are destructed.
The link count is maintained in the header of the
dynamically allocated FlexList.
#include <stdio.h> /* printf() */
#include <flexlist.h>
FlexL FLlinkInit(FlexL L)
{
int *links;
if ((links = FLData(L)) != (int *) 0)
*links = 1;
return L;
}
FLfixedNew
FlexL FLlink(FlexL L)
{
int *links;
if ((links = FLData(L)) != (int *) 0)
++*links;
return L;
}
int FLunlinked(void *LD)
{ /* LD is never NULL! */
int *links = (int *) LD;
if (--*links)
return 0;
return 1;
}
main()
{
FlexL L1, L2;
float f;
if ((L1 = FLlinkInit(FLfixedNew(sizeof(f),
sizeof(int),FLunlinked))) == FlexL0)
return 1;
f = 3.5;
FLpushD(L1,&f);
f = 7.9;
FLinsQD(L1,&f);
L2 = FLlink(L1);
f = 10.1;
FLinsD(L2,&f);
for (FLmkcur(L1,0); FLnextD(L1,&f);
/* no reinit */)
printf("\n%f",f);
FLfixedNew
FLdelete(&L1); /* FLdelete fails! */
printf("\n nodes in L1: %u",FLnodes(L1));
/* three nodes in L2 */
printf("\n nodes in L2: %u",FLnodes(L2));
while (FLnextD(L2,&f))
printf("\n%f",f);
FLdelete(&L2); /* FLdelete succeeds! */
/* FlexList is gone! */
L1 = FlexL0;
printf("\n nodes in L1: %u",FLnodes(L1));
printf("\n nodes in L2: %u",FLnodes(L2));
return 0;
}
The important thing to remember is that FLdelete calls
your FLDdestruct function which must return true before
FLdelete will destruct the FlexList.
You must be careful with alias FlexList pointers. When
FLdelete was called with L1 it don't known that L1 is
an alias for L2 and vice versa. Neither does it know
the scheme of your FLDdestruct function. All FLdelete
knows is that your FLDdestruct function said the
FlexList can't be destructed at this time.
FLfrontD Header, Stack, Queue, & List Access
* Summary
#include <flexlist.h>
void * FLfrontD(FlexL L);
* Return Value
The FLfrontD macro returns a pointer to the data area
of the first node in the list. If there are no nodes
in the list then NULL, i.e. (void *) 0 is returned.
* See Also
FLtopD, FLcurrentD, FLrearD, FLmkcur
* Example
#include <stdio.h> /* printf() */
#include <flexlist.h>
int ints[] = { 1, 2, 3, 4, 5 };
main()
{
FlexList i;
FLunpack(&i,sizeof(ints[0]),sizeof(ints)/
sizeof(ints[0]),ints);
while (*(int *)FLfrontD(&i) != 5)
FLinsQN(&i,FLpopN(&i)); /* roll down */
while (FLnodes(&i)) {
printf("\n%d", *(int *)FLfrontD(&I));
FLpopD(&i,(void *)0); /* trash top node */
}
FLclear(&i);
return 0;
}
This program initializes a FlexList with 5 nodes. It
then "rolls down the stack" until the top node contains
5. It then proceeds to dump and display the stack.
FLinsD List Access
* Summary
#include <flexlist.h>
void * FLinsD(FlexL L, const void *D);
* Description
Inserts a new node after current node and copies the
data, if specified, to the new node. If D is NULL and
the FlexList is variant, FLinsD can't allocate a new
FlexNode since it doesn't know how big to make it.
The newly inserted node becomes the new current node.
If current is undefined prior to the call then the new
node is inserted at the front of the list.
* Return Value
Returns a pointer to the data area of the newly
inserted node. NULL is returned if the function fails.
* See Also
FLinsQD, FLinsSortD, FLpushD, FLdelD, FLinsN
* Example
#include <stdio.h> /* printf() */
#include <flexlist.h>
main() /* count backwards from ten */
{
FlexList l;
int i;
FLfixed(&l,sizeof(int));
for (i = 1; i <= 10; i++)
FLinsD(&l,&i);
while (FLdelD(&l,&i))
printf("\n%d",i);
return 0;
}
FLinsN List Access
* Summary
#include <flexlist.h>
void * FLinsN(FlexL N, FlexN N);
* Description
Inserts the given FlexNode into the FlexList after the
current node. This node becomes the new current node.
If current is undefined then the node is inserted at
the front of the list.
* Return Value
Returns a pointer to the data area of the newly
inserted node. If the operation fails then NULL is
returned.
* See Also
FLdelN, FLpopN, FLinsQN, FLinsSortN, FLpushN, FLinsD
* Example
#include <stdio.h> /* printf() */
#include <flexlist.h>
int ints[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
main()
{
FlexList src, dst;
int i;
FLunpack(&src,sizeof(int),sizeof(ints)/
sizeof(int),ints);
FLfixed(&dst,sizeof(int));
FLmkcur(&src,FLnodes(&src));
while (FLnotFull(&dst) && FLnodes(&src))
FLinsN(&dst,FLdelN(&src));
while (FLpopD(&dst,ints)
printf("\n%d",ints[0]);
return 0;
}
FLinsQD Queue Access
* Summary
#include <flexlist.h>
void * FLinsQD(FlexL L, const void *D);
* Description
Queues a FlexNode onto the end of the FlexList. Copies
the data, if specified, to the new node. If D is NULL
and the FlexList is variant, FLinsQD can't allocate a
new FlexNode since it doesn't know how big to make it.
* Return Value
Returns a pointer to the data area of the new node. If
operation fails it returns NULL.
* See Also
FLinsD, FLinsSortD, FLpushD, FLinsQN
* Example
#include <stdio.h> /* printf() */
#include <flexlist.h>
main()
{
FlexList q;
int i;
FLfixed(&q,sizeof(i));
for (i = 1; i <= 10; i++)
FLinsQD(&q,&i);
while (FLpopD(&q,&i))
printf("\n%d",i);
}
The program queues the integers 1 to 10 and the removes them
one by one from the queue, displaying them.
FLinsQN Queue Access
* Summary
#include <flexlist.h>
void * FLinsQN(FlexL L, FlexN N);
* Description
Queues the given FlexNode onto the end of the FlexList.
* Return Value
Returns a pointer to the data area of the queued node.
If the operation fails it returns NULL.
* See Also
FLinsQD, FLinsN, FLinsSortN, FLpushN
* Example
#include <stdio.h> /* printf() */
#include <flexlist.h>
int ints[] = { 1, 2, 3, 4, 5 };
main()
{
FlexList i;
FLunpack(&i,(sizeof(ints[0]),sizeof(ints)/
sizeof(ints[0]),ints);
while (*(int *)FLfrontD(&i) != 5)
FLinsQN(&i,FLpopN(&i));
while (FLnodes(&i)) {
printf("\n%d",*(int *)FLfrontD(&i));
FLpopD(&i,(void *)0);
}
FLclear(&i);
return 0;
}
The program initializes a FlexList with 5 nodes
containing the integers 1 through 5. The "stack" is
then rolled down until 5 is at the top of the stack.
The nodes are then displayed and discarded: 5, 1, 2, 3,
4.
FLinsSortD List Access
* Summary
#include <flexlist.h>
void * FLinsSortD(FlexL L, const void *D);
* Description
Inserts data into the FlexList in sorted order. The
compare function, previously set by FLsetCompare or
FLsort, specifies the order to insert by returning -1,
0, or 1 indicating that the data in the node under test
is less than, equal to, or greater than the data being
inserted respectively.
FLsort is called automatically prior to the insertion
if the list is not in the sorted order specified by the
compare function.
Note that different compare functions will result in
different sorted orders since the compare function can
be written to test different fields of the data. When
several nodes each contain data that is equal to the
data being inserted, the new data is inserted after the
last of those nodes. The addresses passed to the
compare function point to the whole data areas. The
compare function must apply the test to the appropriate
fields in these data areas. These data areas are
assumed to be the same type as that which the FlexList
was constructed for.
If D is NULL the insertion is aborted.
The binary search algorithm is employed to find the
location to insert the new node. The inserted node
becomes the new current node.
* Return Value
Returns a pointer to the data area of the newly
inserted node. Returns NULL if the operation fails.
* See Also
FLsort, FLfind...D, FLinsSortN
FLinsSortD
* Example
#include <stdio.h> /* printf() */
#include <string.h> /* strcmp() */
#include <flexlist.h>
char *greetings[] = { "hello", "goodbye",
"hi", "bye", "hey there", 0 };
main()
{
FlexList l;
char buf[80];
int i;
FLstr(&l);
FLsetCompare(&l,FLcomparE(strcmp));
for (i = 0; greetings[i]; i++)
FLinsSortD(&l,greetings[i]);
while (FLpopD(&l,buf))
printf("\n%s",buf);
FLclear(&l)
return 0;
}
This program first builds a FlexList of sorted greeting
strings. The FLcomparE macro, defined in flexlist.h,
precisely type casts strcmp to the type required by
FLsetCompare.
FLinsSortN List Access
* Summary
#include <flexlist.h>
void * FLinsSortN(FlexL L, FlexN N);
* Description
Inserts node into the FlexList in sorted order. The
compare function, previously set by FLsetCompare or
FLsort, specifies the order to insert by returning -1,
0, or 1 indicating that the data in the node under test
is less than, equal to, or greater than the data in the
node being inserted respectively.
FLsort is called automatically prior to the insertion
if the list is not in the sorted order specified by the
compare function.
Note that different compare functions will result in
different sorted orders since the compare function can
be written to test different fields of the data. When
several nodes each contain data that is equal to the
data being inserted, the new node is inserted after
last of those nodes. The addresses passed to the
compare function point to the whole data areas. The
compare function must apply the test to the appropriate
fields in these data areas. These data areas are
assumed to be the same type as that which the FlexList
was constructed for.
The binary search algorithm is employed to find the
location to insert the new node. The inserted node
becomes the new current node.
* Return Value
Returns a pointer to the data area of the newly
inserted node. Returns NULL if the operation fails.
* See Also
FLsort, FLfind...D, FLinsSortD
FLinsSortN
* Example
#include <stdio.h> /* printf() */
#include <string.h> /* strcmp() */
#include <flexlist.h>
char *greetings[] = { "hello", "goodbye",
"hi", "bye", "hey there", 0 };
main()
{
FlexList src, dst;
FlexN N;
int i;
FLstr(&src);
for (i = 0; greetings[i]; i++)
FLinsQD(&src,greetings[i]);
FLstr(&dst);
FLsetCompare(&dst,FLcomparE(strcmp));
while (FLnotFull(&dst) && FLnodes(&src))
FLinsSortN(&dst,FLpopN(&src));
while (FLnodes(&dst)) {
printf("\n%s",(char *)FLfrontD(&dst));
N = FLpopN(&dst);
free(N);
}
FLclear(&src); FLclear(&dst);
return 0;
}
This program first builds a FlexList of greeting
strings. It then sorts the list by building a new list
while performing an insertion sort. Lastly, it
displays the sorted strings.
The FLcomparE macro, defined in flexlist.h, precisely
type casts strcmp to the type required by FLsetCompare
(and FLsort).
FLisFixed Header Access
* Summary
#include <flexlist.h>
unsigned FLisFixed(FlexL L);
* Return value
The FLisFixed macro returns true if the FlexList was
constructed with FLfixed, FLfixedNew, FLunpack, or
FLunpackNew.
* Remarks
FLisFixed and FLsizeofNodeData are identical.
* See also
FLsizeofNodeData
* Example
See FLsizeofNodeData example.
FLisSorted Header Access
* Summary
#include <flexlist.h>
int FLisSorted(FlexL L);
* Return value
The FLisSorted macro returns true if no FlexList
functions have been called that could have ruined the
sorted order of the FlexList from the last sort.
* Remarks
Be careful, you can access data in FlexNodes via
FLnextD, FLprevD, and FLmkcur without FLisSorted being
able to detect a ruined sort. If you modify keys in
the data in this manner be sure to call FLunSort to let
the FlexList know it is definitely unsorted.
* See also
FLunSort, FLsort, FLsetCompare
* Example
#include <flexlist.h>
int a[] = { 1, 2, 3, 4, 5 };
int intCompare(int *i1, int *i2)
{ return ((*i1 < *i2)? -1 : (*i1 > *i2)? 1 : 0); }
main()
{
FlexL L;
if ((L = FLunpackNew(sizeof(a[0]),sizeof(a)/
sizeof(a[0]),a)) == FlexL0)
return 1;
/* FLisSorted(L) is false */
FLsort(L,FLcomparE(intCompare));
/* FLisSorted(L) is true */
FLpushD(L,a);
/* FLisSorted(L) is false */
FLdelete(&L);
}
FLisVariant Header Access
* Summary
#include <flexlist.h>
FlexNVFT FLisVariant(FlexL L);
* Return value
The FLisVariant macro returns true if the FlexList was
constructed with FLvariant, FLvariantNew, FLstr, or
FLstrNew.
Actually FLisVariant returns the virtual function table
pointer. The virtual function table pointer is NULL
for non variant FlexLists. FlexNVFT0 is the NULL
pointer constant defined in flexlist.h
* See also
FLisFixed, FLsizeofNodeData
* Example
#include <flexlist.h>
main()
{
FlexList s, q;
FLstr(&s);
FLstr(&q);
FLinsQD(&s,"Now is not the");
FLinsQD(&s,"time for wasting time");
if (FLisVariant(&s) == FLisVariant(&q) &&
FLisVariant(&s) != FlexNVFT0)
FLinsQN(&q,FLpopN(&s));
FLclear(&s);
FLclear(&q);
}
The FlexLists are tested to see if they are compatible
and variant before swapping nodes.
FLmaxNodes Header Access
* Summary
#include <flexlist.h>
unsigned FLmaxNodes(FlexL L);
* Description
The FLmaxNodes macro returns the maximum number of
nodes allowed in the FlexList. FLmaxMaxNodes is the
maximum number of FlexNodes allowed in any FlexList and
is defined in flexlist.h.
* See Also
FLsetMaxNodes, FLnodes, FLnotFull
* Example
#include <stdio.h> /* printf() */
#include <flexlist.h>
main()
{
FlexList q;
int i = 1;
FLfixed(&q,sizeof(int));
printf("\nMax FlexNodes: %u",FLmaxNodes(&q));
printf("\n - Vacancies: %u",FLnotFull(&q));
printf("\n = FlexNodes: %u",FLnodes(&q));
FLsetMaxNodes(&q,35);
FLinsQD(&q,&i);
printf("\nMax FlexNodes: %u",FLmaxNodes(&q));
printf("\n - Vacancies: %u",FLnotFull(&q));
printf("\n = FlexNodes: %u",FLnodes(&q));
FLclear(&q);
return 0;
}
This program limits a queue for integers to a maximum of 35.
FLmkcur List & Array Access
* Summary
#include <flexlist.h>
void * FLmkcur(FlexL L, unsigned n);
* Description
Makes the requested node current. Nodes in a FlexList
are numbered starting at 1. If the requested node is
outside the range of the list then the current node
becomes undefined and curNum is set to 0. It is common
practice to call FLmkcur requesting node 0 in order to
set the current node as undefined. The list is then
ready for processing with the FLnextD or FLprevD
function.
* Return Value
FLmkcur returns a pointer to the data area of the new
current node. If current is undefined, FLmkcur returns
NULL.
* See Also
FLstoreD, FLrecallD, FLnextD, FLprevD, FLcurrentD
* Example
#include <stdio.h> /* printf() */
#include <flexlist.h>
char *txt[] = { "Now is the time",
"for all smarter working",
"programmers to spring for", "FlexList!" };
main() /* walk the list without FLnextD */
{
FlexList l;
char **c;
FLunpack(&l,sizeof(txt[0]),sizeof(txt)/
sizeof(txt[0]),txt);
while ((c = FLmkcur(&l,FLcurNum(&l)+1))
!= (char **) 0)
printf("\n%s",*c);
}
FLnextD List Access
* Summary
#include <flexlist.h>
void * FLnextD(FlexL L, void *D);
* Description
FLnextD makes the next node in the list current. If D
is not NULL, the new current node's data is copied to
the address specified by D. If there is no next node,
current becomes undefined and curNum is set to 0.
* Return Value
FLnextD returns a pointer to the data area of the next
node. If there is no next node, NULL is returned.
* See Also
FLprevD, FLmkcur, FLrecallD, FLstoreD
* Example
#include <stdio.h> /* printf() */
#include <flexlist.h>
char *txt[] = { "Now is the time",
"for all smarter working",
"programmers to spring for",
"FlexList!", 0 };
main() /* display the strings of txt[] */
{
FlexList l;
char buf[80];
int i;
FLstr(&l);
for (i = 0; txt[i]; i++)
FLinsQD(&l,txt[i]);
while (FLnextD(&l,buf))
printf("\n%s",buf);
FLclear(&l);
return 0;
}FLnodes Header Access
* Summary
#include <flexlist.h>
unsigned FLnodes(FlexL L);
* Return Value
The FLnodes macro returns the number of nodes in the
FlexList.
* See Also
FLmaxNodes, FLnotFull
* Example
#include <stdio.h> /* printf() */
#include <flexlist.h>
char *txt[] = { "Now is the time",
"for all smarter working",
"programmers to spring for",
"FlexList!" };
main()
{
FlexList l;
char *c;
FLunpack(&l,sizeof(txt[0]),sizeof(txt)/
sizeof(txt[0]),txt);
while (FLnodes(&l)) {
FLpopD(&l,&c);
printf("\n%s",c);
}
FLclear(&l);
return 0;
}
The program initializes the FlexList with FlexNodes
containing pointers to all the strings of the txt
array. Pointers to the strings are popped and the
strings displayed.
FLnotFull Header Access
* Summary
#include <flexlist.h>
unsigned FLnotFull(FlexL L);
* Return Value
The FLnotFull macro returns the number of nodes that
can still be put into the FlexList. If a FlexList is
full then FLnotFull returns zero which is interpreted
as false, in other words a FlexList that is not
FLnotFull, is full!
* See Also
FLnodes, FLmaxNodes, FLsetMaxNodes
* Example
#include <stdio.h> /* printf() */
#include <flexlist.h>
main()
{
FlexList q;
int i = 1;
FLfixed(&q,sizeof(int));
printf("\nMax FlexNodes: %u",FLmaxNodes(&q));
printf("\n - Vacancies: %u",FLnotFull(&q));
printf("\n = FlexNodes: %u",FLnodes(&q));
FLsetMaxNodes(&q,35);
FLinsQD(&q,&i);
printf("\nMax FlexNodes: %u",FLmaxNodes(&q));
printf("\n - Vacancies: %u",FLnotFull(&q));
printf("\n = FlexNodes: %u",FLnodes(&q));
FLclear(&q);
return 0;
}
FLpack Compaction
* Summary
#include <flexlist.h>
void * FLpack(FlexL L);
* Return Value
FLpack returns the address of an array containing
copies of the data in the all the FlexNodes in the
FlexList. If memory is unavailable or there are no
nodes in the FlexList then FLpack returns NULL. The
array pointer must be type casted to a pointer to the
type of data being stored in the FlexList. When you
are finished with the array it must be explicitly freed
to return its memory to the heap.
* See Also
FLpackPtrs, FLunpack, FLunpackNew
* Remarks
Variant FlexLists can't be packed into a conventional C
array since the FlexNodes are variant length. FLpack
always returns NULL for variant FlexLists.
* Example
#include <stdio.h> /* printf() */
#include <stdlib.h> /* free() */
#include <flexlist.h>
int ints[] = { 40, 70, 23, 5, 67, 2 ,10,
1 , 5, 3, 36, 27 };
int intcmp(int *i1, int *i2)
{ return (*i1 - *i2); }
FLpack
main()
{
FlexList l;
int *intsSorted, i;
FLunpack(&l,sizeof(int),sizeof(ints)/
sizeof(int),ints);
FLsort(&l,FLcomparE(intcmp));
if ((intsSorted = FLpack(&l)) != (int *) 0) {
for (i = 0; i < sizeof(ints)/sizeof(int);
i++)
printf("\n%d",intsSorted[i]);
free(intsSorted);
}
FLclear(&l);
return 0;
}
The FLcomparE macro, defined in flexlist.h, is used to
precisely type cast intcmp to the type required by
FLsort.
FLpackPtrs Compaction
* Summary
#include <flexlist.h>
void ** FLpackPtrs(FlexL L);
* Description
FLpackPtrs allocates enough memory to hold a NULL
terminated array of pointers that point to the data
areas of all the FlexNodes in the FlexList.
* Return Value
If memory is exhausted, FLpackPtrs returns NULL,
otherwise it returns a pointer to an array of void
pointers. You must type cast the void pointers to
pointers to the type of data you are storing in the
FlexList. The array is zero terminated to facilitate
processing. You must explicitly free the array when it
is no longer needed.
* See Also
FLpack, FLunpack, FLunpackNew
* Example
#include <stdio.h> /* printf() */
#include <stdlib.h> /* free() */
#include <flexlist.h>
main()
{
FlexList l; char **c; int i;
FLstr(&l); FLinsQD(&l,"one");
FLinsQD(&l,"two"); FLinsQD(&l,"three");
if ((c = (char **)FLpackPtrs(&l))
!= (char **) 0) {
for (i = 0; c[i]; i++)
printf("\n%s",c[i]);
free(c);
}
FLclear(&l);
return 0;
}
FLpopD Stack & Queue Access
* Summary
#include <flexlist.h>
int FLpopD(FlexL L, void *D);
* Description
FLpopD copies the data from the first node to the
address specified. If no address is given then no data
is copied. FLpopD deletes the first node whether or
not a copy operation is performed.
* Return Value
FLpopD returns 1 if a node was popped, otherwise it
returns 0.
* See Also
FLtopD, FLinsQD, FLpopN, FLpushD, FLdelD, FLinsD
* Example
#include <stdio.h> /* printf() */
#include <flexlist.h>
char *txt[] = { "Now is the time",
"for all smarter working",
"programmers to spring for", "FlexList!" };
main()
{
FlexList q;
char *c;
FLunpack(&q,sizeof(txt[0]),sizeof(txt)/
sizeof(txt[0]),txt);
while (FLpopD(&q,&c))
printf("\n%s",c);
return 0;
}
The program initializes the FlexList with FlexNodes
containing pointers to all the strings of the txt
array. Pointers to the strings are popped and the
strings displayed.
FLpopN Stack & Queue Access
* Summary
#include <flexlist.h>
FlexN FLpopN(FlexL L);
* Description
FLpopN unlinks the first node of the list if there is
one.
* Return Value
FLpopN returns a pointer to the now dangling node or
NULL if there is no node to unlink. The dangling node
must be relinked into a compatible FlexList with a
FlexList function ending with "N" or otherwise
explicitly freed. Two FlexLists are said to be
compatible if the sizes of the data areas in the
FlexNodes are equal. With a variant lists the
sizeofNodeData fields will both be zero. Instead you
should use FLisVariant to make sure the virtual
function table pointers are equal.
* See Also
FLdelN, FLinsQN, FLpopD, FLisVariant
* Example
#include <stdio.h> /* printf() */
#include <string.h> /* strcmp() */
#include <flexlist.h>
char *greetings[] = { "hello", "goodbye",
"hi", "bye", "hey there" };
int StrCmp(char **s1, char **s2)
{ return strcmp(*s1,*s2); }
FLpopN
main()
{
FlexList srcq, dstl;
FLunpack(&srcq,sizeof(greetings[0]),
sizeof(greetings)/sizeof(greetings[0]),
greetings);
FLfixed(&dstl,FLsizeofNodeData(&srcq));
FLsetCompare(&dstl,FLcomparE(StrCmp));
while (FLnotFull(&dstl) && FLnodes(&srcq))
FLinsSortN(&dstl,FLpopN(&srcq));
while (FLnodes(&dstl)) {
printf("\n%s",*(char **)FLfrontD(&dstl));
FLpopD(&dstl,(void *)0);
}
FLclear(&srcq); FLclear(&dstl);
return 0;
}
This program first builds a FlexList of character
pointers to greeting strings. It then sorts the list
by building a new list and performing an insertion
sort. Lastly, it displays the sorted strings. Notice
that the greetings array does not have any 0
terminator. That's okay because the FlexList
constructor is told how many cells there are in the
array.
The FLcomparE macro, defined in flexlist.h, precisely
type casts my compare function pointer to the type
require by both FLsetComare and FLsort.
Please note how I type casted the void pointer returned
by FLfrontD in order to access "by reference" the data
in the front FlexNode.
FLpopD discards the data when popping the top node
because I passed the NULL void pointer as an address.
FLprevD List Access
* Summary
#include <flexlist.h>
void * FLprevD(FlexL L, void *D);
* Description
FLprevD makes the previous node the new current node
and copies data from that node to the address specified
above. If the address is NULL, the copying operation
doesn't take place but the previous node is still made
current. If there is no previous node then current
becomes undefined and curNum is set to 0.
* Return Value
FLprevD returns a pointer to the data area of the
previous node. If there is no previous node, then NULL
is returned.
* See Also
FLnextD, FLmkcur, FLrecallD, FLstoreD
* Example
#include <stdio.h> /* printf() */
#include <flexlist.h>
char *txt[] = { "Now is the time",
"for all smarter working",
"programmers to spring for",
"FlexList!", 0 };
main() /* display the strings of txt[] */
{
FlexList l;
char buf[80];
int i;
FLstr(&l);
for (i = 0; txt[i]; i++)
FLpushD(&l,txt[i]);
while (FLprevD(&l,buf))
printf("\n%s",buf);
FLclear(&l);
return 0;
}FLpushD Stack Access
* Summary
#include <flexlist.h>
void * FLpushD(FlexL L, const void *D);
* Description
Push a new node onto the FlexList "stack." If an
address for data is specified, copy that data to the
new node. If D is NULL and the FlexList is variant,
FLpushD can't allocate a new FlexNode since it doesn't
know how big to make it.
* Return Value
FLpushD returns a pointer to the data area of the newly
pushed node. If dynamic memory is exhausted or FLpushD
is otherwise unable to push a new node, NULL, i.e.
(void *) 0, is returned.
* See Also
FLpopD, FLpushN, FLinsD, FLinsQD, FLinsSortD
* Example
#include <stdio.h> /* printf() */
#include <flexlist.h>
char *txt[] = { "Now is the time",
"for all smarter working",
"programmers to spring for", "FlexList!", 0 };
main() /* stack char pointers */
{
FlexList s;
char *c;
int i;
FLfixed(&s,sizeof(txt[0]));
for (i = 0; txt[i]; i++)
FLpushD(&s,&txt[i]);
while (FLpopD(&s,&c))
printf("\n%s",c); /* read lines backward */
}
FLpushN Stack Access
* Summary
#include <flexlist.h>
void * FLpushN(FlexL L, FlexN N);
* Description
FLpushN relinks the given FlexNode onto the front of
the FlexList.
* Return Value
FLpushN returns a pointer to the data area of the node
just pushed. If FLpushN fails to push the node, it
returns NULL, i.e. FlexN0 defined in flexlist.h.
* See Also
FLpopN, FLinsQN, FLinsN, FLdelN, FLinsSortN, FLpushD
* Example
#include <stdio.h> /* printf() */
#include <flexlist.h>
char *txt[] = { "Now is the time",
"for all smarter working",
"programmers to spring for", "FlexList!" };
main()
{
FlexList l, s;
char *c;
FLunpack(&l,sizeof(txt[0]),sizeof(txt)/
sizeof(txt[0]),txt);
FLfixed(&s,FLsizeofNodeData(&l));
while (FLnotFull(&s) && FLnodes(&l))
FLpushN(&s,FLpopN(&l));
while (FLpopD(&s,&c))
printf("\n%s",c); /* read lines backward */
return 0;
}
FLrearD Header & Queue Access
* Summary
#include <flexlist.h>
void * FLrearD(FlexL L);
* Return Value
The FLrearD macro returns a pointer to the data area of
the rear node. If there are no nodes in the list it
returns NULL, i.e. (void *) 0.
* See Also
FLfrontD, FLcurrentD, FLnextD, FLprevD
* Example
#include <stdio.h> /* printf() */
#include <flexlist.h>
char *txt[] = { "FlexList!",
"programmers to spring for",
"for all smarter working",
"Now is the time" };
main()
{
FlexList q;
char **c;
FLunpack(&q,(sizeof(txt[0]),sizeof(txt)/
sizeof(txt[0]),txt);
FLmkcur(&q,FLnodes(&q));
while ((c = FLrearD(&q)) != (char **)0) {
printf("n%s",*c);
FLdelD(&q,(void *)0);
}
}
The last node is made current to enable FLdelD to walk
across the list backwards. A pointer to the data in
the rear node is used to display the string.
FLrecallD Array Access
* Summary
#include <flexlist.h>
int FLrecallD(FlexL L, void *D, unsigned n);
* Description
FLrecallD copies the data from the requested node, n,
to the address specified by D. If the address is NULL
the operation is aborted. If the requested node is
zero the current node is recalled. If the requested
node is out of range the operation is again aborted.
FLmkcur is called internally by FLrecallD to make the
requested node current. FLmkcur determines which
pointer (front, current, or rear) is closest to the
requested node. It then follows the FlexList's linkage
from that closest pointer to the newly requested node.
The current pointer is left positioned at the new node.
* Return Value
FLrecallD returns 1 if successful, 0 otherwise.
* See Also
FLstoreD, FLmkcur
* Example
#include <stdio.h> /* printf() */
#include <flexlist.h>
char *txt[] = { "Now is the time",
"for all smarter working",
"programmers to spring for",
"FlexList!", (char *) 0 };
FLrecallD
main()
{
FlexList l;
char buf[80];
int i;
FLstr(&l);
for (i = 0; txt[i]; i++)
FLinsQD(&l,txt[i]);
for (i = 1; FLrecallD(&l,buf,i); i++)
printf("\n%s",buf);
FLclear(&l);
return 0;
}
Program output:
Now is the time
for all smarter working
programmers to spring for
FlexList!
FLsetCompare Header Access
* Summary
#include <flexlist.h>
int FLsetCompare(
FlexL L,
int (*compare)
(const void *D1, const void *D2)
);
* Description
FLsetCompare sets the FlexList's internal compare
function pointer to point to a user defined compare
function. Your compare function returns -1, 0, or 1 to
indicate whether the first data being compared is less
than, equal to, or greater than the second,
respectively. The compare function is used by FLsort,
FLinsSortN, and FLinsSortD. The compare function is
also used for matching in FLfindFirstD, FLfindNextD,
FLfindLastD, and FLfindPrevD.
* Return value
FLsetCompare returns true if L is not NULL.
* Remarks
It is common to have several different compare
functions to search or sort a FlexList on various keys,
in various orders.
If you want to inhibit FlexList's binary searches and
sorts then call FLsetCompare with FLcompare0, the NULL
compare function pointer constant defined in
flexlist.h.
* See also
FLsort, FLcompare, FLisSorted, FLunSort, FLfindFirstD,
FLfindNextD, FLfindLastD, FLfindPrevD
FLsetCompare
* Example
#include <stdio.h> /* printf() */
#include <flexlist.h>
int a[] = { 101, 2, 6, 3, 2, 8, 9, 13, 56 };
int intMatch(int *i1, int *i2)
{ return !(*i1 == *i2); }
main()
{
FlexList l;
int i = 2;
FLunpack(&l,sizeof(a[0]),sizeof(a)/
sizeof(a[0]),a);
FLsetCompare(&l,FLcomparE(intMatch));
if (FLfindFirstD(&l,&i))
printf("\nFound %d in node %d : %d",
i,FLcurNum(&l),*(int *)FLcurrentD(&l));
FLclear(&l);
return 0;
}
Please note that the compare function only matches and
doesn't reveal an ordering. Don't call FLinsSortD or
another function requiring the compare function to act
as the test in a binary search - it will only be very
confused since greater than and less than conditions
can't be determined!
The FLcomparE macro is used to precisely type cast my
match function to the compare type required by FLsort
and FLsetCompare. It is defined in flexlist.h.
FLsetMaxNodes Header Access
* Summary
#include <flexlist.h>
int FLsetMaxNodes(FlexL L, unsigned maxNodes);
* Description
FLsetMaxNodes set the upper limit on FlexNodes that a
FlexList is allowed to contain. FLmaxMaxNodes is
defined in flexlist.h as the maximum number allowed in
any FlexList.
* Return value
FLsetMaxNodes returns true if it is successful in
establishing the new limit. The new limit must be
greater than or equal to the number of nodes already in
the FlexList.
* See also
FLmaxNodes, FLnodes, FLnotFull
* Example
#include <stdio.h> /* printf() */
#include <flexlist.h>
main()
{
FlexList q;
int i = 1;
FLfixed(&q,sizeof(int));
printf("\nMax FlexNodes: %u",FLmaxNodes(&q));
printf("\n - Vacancies: %u",FLnotFull(&q));
printf("\n = FlexNodes: %u",FLnodes(&q));
FLsetMaxNodes(&q,35);
FLinsQD(&q,&i);
printf("\nMax FlexNodes: %u",FLmaxNodes(&q));
printf("\n - Vacancies: %u",FLnotFull(&q));
printf("\n = FlexNodes: %u",FLnodes(&q));
FLclear(&q);
return 0;
}
FLsizeofNodeData Header Access
* Summary
#include <flexlist.h>
unsigned FLsizeofNodeData(FlexL L);
* Return Value
The FLsizeofNodeData macro returns the sizeofNodeData
field in the FlexList's header. The sizeofNodeData
field tells FlexList functions how big the data is that
is warehoused in the FlexList. FlexLists are said to
be compatible if their data sizes are equal. Only
FlexLists that are compatible can have their nodes
swapped.
* Remarks
Variant FlexLists have their sizeofNodeData fields set
to zero. This is because the data size is unknown -
the virtual functions determine that. If two FlexLists
use the same virtual function table, their data are
most likely compatible. You'll have to make that
determination. Use FLisVariant to retrieve a pointer
to a FlexList's virtual function table.
* See Also
FLfixed, FLvariant
* Example
#include <flexlist.h>
int a[] = { 1, 2, 3, 4, 5 };
main()
{
FlexList s, q;
FLunpack(&s,sizeof(a[0]),sizeof(a)/
sizeof(a[0]),a);
FLfixed(&q,FLsizeofNodeData(&s));
while (FLnotFull(&q) && FLnodes(&s))
FLpushN(&q,FLpopN(&s));
...
FLclear(&s);
FLclear(&q);
}
FLsort Sort
* Summary
#include <flexlist.h>
int FLsort(
FlexL L,
int (*compare)(
const void *D1,
const void *D2
)
);
* Description
Sorts the FlexList in the order specified by compare.
The compare function specifies the order to sort by
returning -1, 0, or 1 indicating that the data in the
node under test is less than, equal to, or greater than
the data in the node being moved respectively. Note
that different compare functions will result in
different sorted orders since the compare function can
be written to test different fields of the data. The
addresses passed to the compare functions point to the
whole data areas. The compare function must apply the
test to the appropriate fields in these data areas.
These data areas are assumed to be the same type as
that which the FlexList was constructed for. The
binary search algorithm is employed.
FLsort resets the current node as undefined.
* See Also
FLfind...D, FLinsSortD, FLinsSortN
* Example
#include <stdio.h> /* printf() */
#include <string.h> /* strcmp() */
#include <flexlist.h>
char *greetings[] = { "hello", "goodbye",
"hi", "bye", "hey there", (char *) 0 };
FLsort
main()
{
FlexList l;
char buf[80];
int i;
FLstr(&l);
for (i = 0; greetings[i]; i++)
FLinsQD(&l,greetings[i]);
printf("\nUnsorted:");
while (FLnextD(&l,buf))
printf("\n%s",buf);
FLsort(&l,FLcomparE(strcmp));
printf("\n\nSorted:");
while (FLnextD(&l,buf))
printf("\n%s",buf);
FLclear(&l);
return 0;
}
This program first builds a FlexList of greeting
strings. It then sorts the list.
The FLcomparE macro, defined in flexlist.h, precisely
type casts my compare function pointer to the type
required by FLsort.
FLstoreD Array Access
* Summary
#include <flexlist.h>
int FLstoreD(FlexL L, const void *D, unsigned n);
* Description
FLstoreD writes the data specified into the node
specified. If n is 0, then the current node is assumed
to be the node to store in. If the data's address is
NULL the operation is aborted or if the requested node
is out of range of the FlexList.
FLmkcur is called internally by FLstoreD to make the
requested node current. FLmkcur determines which
pointer (front, current, or rear) is closest to the
requested node. It then follows the FlexList's linkage
from that closest pointer to the newly requested node.
The current pointer is left positioned at the new node.
* Return Value
If successful FLstoreD returns 1, otherwise 0.
* Remarks
With variant FlexLists, e.g. those created with FLstr,
etc., the writing of data is limited to the length of
the data already present in the node. This makes sense
since the FlexNode is just big enough to accommodate
the former data.
* See Also
FLrecallD, FLmkcur, FLstr, FLvariant
* Example
#include <stdio.h> /* printf() */
#include <flexlist.h>
char *txt[] = { "Now is the time",
"for all smarter working",
"programmers to spring for",
"FlexList!", (char *) 0 };
FLstoreD
main()
{
FlexList l;
char buf[80];
int i;
FLstr(&l);
for (i = 0; txt[i]; i++)
FLinsQD(&l,txt[i]);
FLstoreD(&l,"for all overworked and tired",2);
FLmkcur(&l,0);
while (FLnextD(&l,buf))
printf("\n%s",buf);
FLclear(&l);
return 0;
}
Program output:
Now is the time
for all overworked
programmers to spring for
FlexList!
FLstr Static Constructor
* Summary
#include <flexlist.h>
FlexL FLstr(FlexL L);
* Description
The FLstr macro expands into a call to FLvariant with a
virtual function table for processing C strings. The
FlexList is initialized to contain only FlexNodes big
enough for the C strings held within. All FlexLists
functions are available; however, FLstoreD will limit
the string being stored to the length of the string it
is overwriting. This prevents FLstoreD from writing
pass the end of the FlexNode.
* Return value
FLstr returns L if successful otherwise it returns
FlexL0, the NULL FlexList pointer defined in
flexlist.h.
* Remarks
When copying data from variant string FlexLists, you
must insure that the receiving string buffer is big
enough to accommodate the largest string that may be
encountered.
Be sure to read on the section on FLvariant for an
explanation of how FLstr works.
* See also
FLstrNew, FLvariant
FLstr
* Example
#include <stdio.h> /* printf() */
#include <flexlist.h>
main()
{
FlexList l;
char s[80];
FLstr(&l);
FLinsQD(&l,"one dog");
FLinsQD(&l,"two cats");
FLinsQD(&l,"three crows");
while (FLnextD(&l,s))
printf("\n%s",s);
FLstoreD(&l,"three cat birds",FLnodes(&l));
/* truncates to length of "three crows"! */
FLsort(&l,FLcomparE(strcmp));
FLmkcur(&l,0);
while (FLnextD(&l,s))
printf("\n%s",s);
FLclear(&l);
return 0;
}
The FLcomparE macro, defined in flexlist.h, precisely
type casts to the function pointer type required by the
FLsort and FLsetCompare functions.
FLstrNew Dynamic Constructor
* Summary
#include <flexlist.h>
FlexL FLstrNew(size_t sizeofLocalData,
int (*FLDdestruct)(void *LD));
* Description
The FLstrNew macro expands to a call to FLvariantNew
which dynamically allocates and initializes a FlexList
with room enough in the header to store user data of
the size sizeofLocalData and the FlexNodes just big
enough to hold C strings. FLDdestruct is the user
defined function that must be successfully called by
FLdelete before a FlexList will be cleared and
deallocated. FLDdestruct is called with the address of
the user data in the FlexList header. It must return a
non zero value if the FlexList is every to be disposed
of.
* Return value
FLstrNew returns a pointer to the newly allocated
FlexList or FlexL0 if it fails. FlexL0 is the NULL
FlexList pointer constant defined in flexlist.h
* Remarks
Be sure to read the entries for FLstr and FLvariant and
FLvariantNew to better understand the operation of
variant FlexLists.
* See also
FLstr, FLvariant, FLvariantNew, FLdelete
* Example
See examples for FLvariant, FLvariantNew, FLfixedNew
FLtopD Stack & Queue Access
* Summary
#include <flexlist.h>
void * FLtopD(FlexL L, void *D);
* Description
FLtopD fetches a copy of the data in the first node of
the list if an address is specified for D.
* Return Value
If there are no nodes then FLtopD returns NULL
otherwise FLtopD returns a pointer to the data area of
the top node.
* See Also
FLfrontD, FLpopD
* Example
#include <stdio.h> /* printf() */
#include <flexlist.h>
int ints[] = { 1, 2, 3, 4 };
main()
{
FlexList s;
int i;
FLunpack(&s,sizeof(ints[0]),sizeof(ints)/
sizeof(ints[0]),ints);
while (FLtopD(&s,&i)) {
printf("\n%d",i);
FLpopD(&s,(void *)0);
}
}
The program initializes the FlexList to hold four
integers. The integers are displayed and popped.
FLunpack Static Constructor
* Summary
#include <flexlist.h>
FlexL FLunpack(FlexL L, size_t sizeofCell,
unsigned cells, const void *array);
* Description
This FlexList constructor initializes the FlexList
pointed to by L with enough FlexNodes of the proper
size to hold all the cells of the specified array.
Each node contains a copy of one cell of the given
array. You can think of this constructor as exploding
a conventional C array into a FlexList. MaxNodes is
set to FLmaxMaxNodes, the maximum allowed for any
FlexList which is UINT_MAX (the largest value of an
unsigned integer).
* Return value
If successful, FLunpack returns L otherwise it returns
FlexL0 which is defined in flexlist.h as (FlexL) 0.
* See Also
FLunpackNew, FLpack, FLpackPtrs, FLfixed
* Example
#include <flexlist.h>
float f[] = { 1.5, 2.1, 3.7, 4.4, 5.1 };
main() /* add zero to front of array */
{
FlexList l;
float F = 0.0;
(void) FLunpack( &l, sizeof(f[0]), sizeof(f) /
sizeof(f[0]), f);
(void) FLpushD(&l,&F);
...
}
FLunpackNew Dynamic Constructor
* Summary
#include <flexlist.h>
FlexL FLunpackNew(
size_t sizeofCell,
unsigned cells,
const void *array,
size_t sizeofLocalData,
int (*FLDdestruct)(void *LD)
);
* Description
This FlexList constructor allocates and initializes a
FlexList with enough FlexNodes of the proper size to
hold all the cells of the specified array. Each node
contains a copy of one cell of the given array. You
can think of this constructor as exploding a
conventional C array into a FlexList. MaxNodes is set
to FLmaxMaxNodes, the maximum allowed for any FlexList
which is UINT_MAX (the largest value of an unsigned
integer).
The FlexList header is allocated large enough to hold
user data of the size specified by sizeofLocalData.
Use FLdelete to destruct dynamically allocated
FlexLists. FLdelete calls the user defined function
FLDdestruct which is passed the address of user data in
the FlexList header (the address is never NULL). If
your FLDdestruct function returns something other than
zero, FLdelete will then call FLclear to destruct the
FlexNodes and if that is successful, FLdelete then
frees the dynamically allocated FlexList. If your
FLDdestruct function returns zero then FLdelete will
return zero.
* Return value
If successful, FLunpackNew returns a pointer to a
dynamically allocated FlexList, otherwise it returns
FlexL0 which is defined in flexlist.h as (FlexL) 0.
FLunpackNew
* Remarks
If your dynamic FlexList doesn't need to store data in
the FlexList header then pass zero to the
sizeofLocalData parameter.
If your application doesn't require a FLDdestruct
function call FLunpackNew with the NULL pointer
constant, FLDdestruct0, defined in flexlist.h.
If your dynamic FlexList doesn't store data in the
FlexList header, don't access data with FLData!
Likewise if you do specify a FLDdestruct function, be
sure your function ignores the local data parameter
passed to it! A Flexlist doesn't maintain a
sizeofLocalData field from which it can ascertain
whether or not you store any data in the FlexList
header. This was a design consideration to save space
in the header.
Use FLData and FLisFixed to determine if a FlexList was
constructed with FLfixedNew or FLunpackNew. FLData
returns true for dynamically allocated FlexLists.
* See Also
FLData, FLdelete, FLisFixed, FLunpack, FLpack,
FLpackPtrs, FLfixed
* Example
This program builds a list of floats and then aliases
it. When FLdelete is called it won't destruct the
FlexList until all references to it are destructed.
The link count is maintained in the header of the
dynamically allocated FlexList.
#include <stdio.h> /* printf() */
#include <flexlist.h>
FLunpackNew
FlexL FLlinkInit(FlexL L)
{
int *links;
if ((links = FLData(L)) != (int *) 0)
*links = 1;
return L;
}
FlexL FLlink(FlexL L)
{
int *links;
if ((links = FLData(L)) != (int *) 0)
++*links;
return L;
}
int FLunlinked(void *LD)
{ /* LD is never NULL! */
int *links = (int *) LD;
if (--*links)
return 0;
return 1;
}
FLunpackNew
float f[] = { 3.5, 7.9, 10.1 }
main()
{
FlexL L1, L2;
if ((L1 = FLlinkInit(FLunpackNew(sizeof(f[0]),
sizeof(f)/sizeof(f[0]),f,
sizeof(int),FLunlinked))) == FlexL0)
return 1;
L2 = FLlink(L1);
while (FLnextD(L1,&f))
printf("\n%f",f);
FLdelete(&L1); /* FLdelete fails! */
printf("\n nodes in L1: %u",FLnodes(L1));
/* three nodes in L2 */
printf("\n nodes in L2: %u",FLnodes(L2));
while (FLnextD(L2,&f))
printf("\n%f",f);
FLdelete(&L2); /* FLdelete succeeds! */
/* FlexList is gone! */
L1 = FlexL0;
printf("\n nodes in L1: %u",FLnodes(L1));
printf("\n nodes in L2: %u",FLnodes(L2));
return 0;
}
The important thing to remember is that FLdelete calls
your FLDdestruct which must return true before FLdelete
will destruct the FlexList.
FLunSort Header Access
* Summary
#include <flexlist.h>
int FLunSort(FlexL L);
* Return value
The FLunSort macro returns true if L is not NULL. The
sorted field in the FlexList header is reset to zero.
* Remarks
FLunSort is used primarily after a sort and subsequent
key data modification via a pointer returned by
FLnextD, FLprevD, or FLmkcur. Any other modifications
to the FlexList's sorted order can be determined
automatically.
* See Also
FLsort, FLisSorted
* Example
#include <flexlist.h>
int a[] = { 1, 2, 3, 4, 5 };
int intCompare(int *i1, int *i2)
{ return ((*i1 < *i2)? -1 : (*i1 > *i2)? 1 : 0); }
main()
{
FlexList l;
FLunpack(&l,sizeof(a[0]),sizeof(a)/
sizeof(a[0]),a);
/* FLisSorted(&l) is false */
FLsort(&l,FLcomparE(intCompare));
/* FLisSorted(&l) is true */
*(int *)FLmkcur(&l,1) = 6;
/* FLisSorted(&l) is true */
FLunSort(&l);
/* FLisSorted(&l) is false */
FLclear(&l);
}
FLvariant Static Constructor
* Summary
#include <flexlist.h>
FlexL FLvariant(FlexL L, FlexNVFT vft);
* Description
FLvariant initializes the FlexList pointed to by L to
hold variant length data. Vft is a pointer to the
virtual function table containing the pointers to user
defined functions. These functions tell the FlexList
functions 1) how to create a new FlexNode from user
data, 2) how to write user data to a FlexNode, 3) how
to read user data from a FlexNode, and 4) how to
dispose of user data when deleting a FlexNode. These
virtual functions allow a FlexList to handle most types
of heterogeneous data.
The sizeofNodeData field within the FlexList header is
always zero for variant FlexLists.
* Return value
If successful, FLvariant returns L otherwise it returns
FlexL0 which is defined in flexlist.h as (FlexL) 0.
* Remarks
You must define four functions:
FlexN FNnew(const void *D);
int FNwrite(void *ND, const void *D);
int FNread(const void *ND, void *D);
int FNdestruct(void *ND, void *D);
The above parameters are guaranteed never to be NULL
except possibly the D in FNdestruct. You can name your
functions any way you like. Return zero for all four
functions if there is a failure, otherwise the FlexList
function invoking them will assume that all is well and
proceed. If you want to inhibit a particular function
just return zero for that function and any FlexList
function requiring that function will return failure
and in effect be inhibited for the life of your variant
FlexList.
FLvariant
You must then define and initialize a virtual function
table:
FlexNodeVFT YourVFT = { FNnew, FNwrite,
FNread, FNdestruct };
Any of the virtual functions can be absent. Use
FNnew0, FNwrite0, FNread0, and/or FNdestruct0 as zero
initializers. The FlexList functions that call them
will simply return a failure indication.
In this case the call to construct the FlexList would
be:
FlexList l;
FLvariant(&l,&YourVFT);
The FlexList functions that access user data by value
will now work on your variant data the same way they
did for fixed sized data. You can think of these
virtual functions as user definable hooks that FlexList
"by value" functions call to allow the user's data to
define its own size and how it's to be copied.
Let's look at which FlexList functions use each virtual
function.
FNnew FLpushD, FLinsQD, FLinsD, and
FLinsSortD
FNwrite FLstoreD
FNread FLtopD, FLnextD, FLprevD, FLrecallD
FNdestruct FLpopD, FLdelD, FLclear via FLpopD,
FLdelete via FLclear via FLpopD
For example when FLpushD is called for a variant
FlexList, FLpushD knows that it is a variant FlexList
because the sizeofNodeData field in the FlexList's
header is zero. If the address of the data has been
passed to FLpushD it then checks if the virtual
function table is initialized with a function pointer
for FNnew. If so your FNnew is called with the address
of the data passed to FLpushD.
FLvariant
Your FNnew must determine how big the data is and
allocate an appropriate FlexNode and copy the data to
it. If your FNnew is successful it returns a pointer
to the newly allocated FlexNode initialized with a copy
of your data. Your FNnew indicates failure by
returning FlexN0, the NULL FlexNode pointer constant
defined in flexlist.h.
FlexN YourFNnew(const void *D)
{ /* D is never NULL! */
FlexN N;
if ((N = malloc( sizeof(FlexNode) +
sizeofYourData(D)-1)) != FlexN0)
memcpy(N->data,D,sizeofYourData(D));
return N;
}
Basically you need to allocate a FlexNode for the "size
of your data" plus the sizeof(FlexNode) minus one.
It's up to you to figure out how to get your data
copied into the FlexNode. Just remember to start your
copying at N->data! You may even have suballocated
dynamic memory to worry about. Don't just copy
embedded pointers to suballocated dynamic memory along
with the data since two data structures would then
"own" the memory pointed to.
Writing to a FlexNode is very similar to creating a new
initialized FlexNode except the FlexNode doesn't have
to be allocated. You need to be careful since you
don't want to overwrite the end of the FlexNode with
data that is longer than was originally in there!
int YourFNwrite(void *ND, const void *D)
{ /* ND and D are never NULL! */
if (sizeofYourData(ND) < sizeofYourData(D))
return 0;
memcpy(ND,D,sizeofYourData(D));
return 1;
}
Again you need to consider embedded pointers, etc.
FLvariant
Let's look at a possible FNread function that simply
copies the FlexNode data area "ND" to your data "D."
int YourFNread(const void *ND, void *D)
{ /* ND and D are never NULL! */
memcpy(D,ND,sizeofYourData(ND));
return 1;
}
Again your data may be a complicated C structure with
suballocated memory. Whatever scheme you use to
resolve double ownership of suballocated memory, make
sure you keep it straight and don't leave dangling
memory lying about by overwriting pointers in D!
Let's take a look at a simple FNdestruct function.
int YourFNdestruct(void *ND, void *D)
{ /* ND is never NULL; D may be NULL! */
if (D)
memcpy(D,ND,sizeofYourData(ND));
else {
/* free any suballocated memory */
}
return 1;
}
Again you must be sure not to overwrite pointers in D
without first deallocating any suballocated memory.
This time D might be NULL in which case you must be
sure to deallocate any suballocated memory since the
FlexNode will be discarded soon after your function
returns. I'm assuming that embedded pointers copied to
D transfer suballocated memory to D.
* See also
FLvariantNew, FLstr, FLfixed
* Example
For our first example, let's see how FLstr constructs a
variant FlexList for C strings.
FLvariant
#include <stdio.h> /* printf() */
#include <string.h> /* strcmp() */
#include <flexlist.h>
#ifdef definedInFlexlistC
static FlexN FNnewStr(const void *D)
{
FlexN N;
size_t i;
for (i = 0; ((char *)D)[i++]; /* no reinit */)
/* null statement */;
if ((N = malloc(sizeof(FlexNode)+i-1)) != FlexN0)
(void) memcpy(N->data,D,i);
return N;
}
static int FNwriteStr(void *ND, const void *D)
{
char *nd, *d;
nd = (char *) ND;
d = (char *) D;
while (*nd)
if ((*nd++ = *d++) == '\0')
break;
return 1;
}
static int FNreadStr(const void *ND, void *D)
{
char *nd, *d;
nd = (char *) ND;
d = (char *) D;
while ((*d++ = *nd++) != '\0')
/* null statement */;
return 1;
}
FLvariant
static int FNdestructStr(void *ND, void *D)
{
char *nd, *d;
nd = (char *)ND;
if ((d = (char *)D) != (char *)0)
while ((*d++ = *nd++) != '\0')
/* null statement */;
return 1;
}
FlexNodeVFT FlexNodeStrVFT = { FNnewStr, FNwriteStr,
FNreadStr, FNdestructStr };
#endif
#ifdef definedInFlexlistH
#define FLstr(L) FLvariant(L,&FlexNodeStrVFT)
#endif
main()
{
FlexList l;
char s[80];
FLstr(&l);
FLinsQD(&l,"one dog"); /* calls FNnew */
FLinsQD(&l,"two cats");
FLinsQD(&l,"three crows");
while (FLnextD(&l,s)) /* calls FNread */
printf("\n%s",s);
FLstoreD(&l,"three cat birds",FLnodes(&l));
/* calls FNwrite which truncates! */
FLsort(&l,FLcomparE(strcmp));
FLmkcur(&l,0);
while (FLnextD(&l,s))
printf("\n%s",s);
FLclear(&l); /* calls FNdestruct via FLpopD */
return 0;
}
FLcomparE is defined in flexlist.h and does a precise
type cast to the function pointer type required by the
FLsort and FLsetCompare functions.
FLvariant
In the second example, a FlexList is used to warehouse
messages that have suballocated text strings. A
variant FlexList is used to control suballocated
dynamic memory in what would otherwise be a fixed sized
FlexNode FlexList. The virtual functions are used to
control the allocating and deallocating of the
suballocated memory and thus prevent suballocated
memory from being doubly owned or left dangling.
The msgcpy function insures that the destination
message's text string is freed before copying the
source message. The source message's text string is
duplicated in the destination message. FNdestructMsg
frees the text string before returning to the calling
FlexList function which will in turn free the FlexNode.
#include <stdio.h> /* printf() */
#include <stdlib.h> /* malloc(), free() */
#include <string.h> /* strlen(), strcpy() */
/* memcpy() */
#include <flexlist.h>
typedef struct {
unsigned token;
char *text;
} msg, *msG;
void msgput(msG M)
{
if (M)
printf("\n Token: %8u text: %s",
M->token,M->text);
}
char *strdup(const char *s)
{
char *t;
if (s)
if ((t = malloc((size_t)strlen(s)+1))
!= (char *) 0)
return strcpy(t,s);
return (char *) 0;
}
FLvariant
static void msgcpy(msG Mdst, msG Msrc)
{ /* Mdst and Msrc are never NULL! */
if (Mdst->text)
free(Mdst->text);
(void) memcpy(Mdst,Msrc,sizeof(msg));
Mdst->text = strdup(Msrc->text);
}
FlexN FNnewMsg(const void *D)
{ /* D is never NULL! */
FlexN N;
if ((N = malloc(sizeof(msg)+sizeof(FlexNode)-1))
!= FlexN0) {
((msG)(N->data))->text = (char *) 0;
msgcpy((msG)(N->data),(msG)D);
}
return N;
}
int FNwriteMsg(void *ND, const void *D)
{ /* ND and D are never NULL! */
msgcpy((msG)ND,(msG)D);
return 1;
}
int FNreadMsg(const void *ND, void *D)
{ /* ND and D are never NULL! */
msgcpy((msG)D,(msG)ND);
return 1;
}
int FNdestructMsg(void *ND, void *D)
{ /* ND is never NULL; D may be NULL! */
if (D)
msgcpy((msG)D,(msG)ND);
if (((msG)ND)->text)
free(((msG)ND)->text);
return 1;
}
FlexNodeVFT FLmsgVFT = { FNnewMsg, FNwriteMsg,
FNreadMsg, FNdestructMsg };
FLvariant
main()
{
FlexList m;
msg M;
FLvariant(&m,&FLmsgVFT);
M.token = 1; M.text = "one dog";
FLinsQD(&m,&M); /* calls FNnew */
M.token = 2; M.text = "two cats";
FLinsQD(&m,&M);
M.token = 3; M.text = "three crows";
FLinsQD(&m,&M);
/* don't free string constant */
M.text = (char *) 0;
while (FLnextD(&m,&M)) /* calls FNread */
msgput(&M);
M.token = 3; M.text = "three cat birds";
FLstoreD(&m,&M,FLnodes(&m)); /* calls FNwrite */
FLmkcur(&m,0);
/* don't free string constant */
M.text = (char *) 0;
while (FLnextD(&m,&M))
msgput(&M);
FLclear(&m); /* calls FNdestruct via FLpopD */
return 0;
}
FLvariantNew Dynamic Constructor
* Summary
#include <flexlist.h>
FlexL FLvariantNew(
FlexNVFT vft,
size_t sizeofLocalData,
int (*FLDdestruct)(void *LD)
);
* Description
FLvariantNew allocates and initializes a FlexList big
enough to hold user data within the FlexList header.
The FlexList can subsequently be used to warehouse
variant data in the FlexNodes of the type handled by
the virtual function table. Vft is a pointer to the
virtual function table containing the pointers to user
defined functions. These functions tell the FlexList
functions 1) how to create a new FlexNode from user
data, 2) how to write user data to a FlexNode, 3) how
to read user data from a FlexNode, and 4) how to
dispose of user data when deleting a FlexNode. These
virtual functions allow a FlexList to handle most types
of heterogeneous data.
The FlexList header can warehouse data of the size
sizeofLocalData. Use FLdelete to destruct dynamically
allocated FlexLists. FLdelete calls the user defined
function FLDdestruct which is passed the address of
user data in the FlexList header (the address is never
NULL). If your FLDdestruct function returns something
other than zero, FLdelete will then call FLclear to
destruct the FlexNodes and if that is successful,
FLdelete then frees the dynamically allocated FlexList.
If you FLDdestruct function returns zero then FLdelete
will return zero.
MaxNodes is set to FLmaxMaxNodes, the maximum allowed
for any FlexList which is UINT_MAX (the largest value
of an unsigned integer).
The sizeofNodeData field within the FlexList header is
always zero for variant FlexLists.
FLvariantNew
* Return value
If successful, FLvariantNew returns a pointer to a
dynamically allocated FlexList, otherwise it returns
FlexL0 which is defined in flexlist.h as (FlexL) 0.
* Remarks
If your dynamic FlexList doesn't need to store data in
the FlexList header then pass zero to the
sizeofLocalData parameter.
If your application doesn't require a FLDdestruct
function call FLfixedNew with the NULL pointer
constant, FLDdestruct0, defined in flexlist.h.
If your dynamic FlexList doesn't store data in the
FlexList header, don't access data with FLData!
Likewise if you do specify a FLDdestruct function, be
sure your function ignores the local data parameter
passed to it! A Flexlist doesn't maintain a
sizeofLocalData field from which it can ascertain
whether or not you store any data in the FlexList
header. This was a design consideration to save space
in the header.
Use FLData and FLisVariant to determine if a FlexList
was constructed with FLvariantNew. FLData returns true
for dynamically allocated FlexLists.
Be sure to read the previous entry for FLvariant to
gain an understanding of how variant FlexLists operate.
* See Also
FLData, FLdelete, FLisVariant, FLvariant, FLfixed
* Example
This program builds a list of C strings and then
aliases it. When FLdelete is called it won't destruct
the FlexList until all references to it are destructed.
The link count is maintained in the header of the
dynamically allocated FlexList.
FLvariantNew
#include <stdio.h> /* printf() */
#include <string.h> /* strcmp() */
#include <flexlist.h> /* FlexL0, FLcomparE */
/* FlexNodeStrVFT */
FlexL FLlinkInit(FlexL L)
{
int *links;
if ((links = FLData(L)) != (int *) 0)
*links = 1;
return L;
}
FlexL FLlink(FlexL L)
{
int *links;
if ((links = FLData(L)) != (int *) 0)
++*links;
return L;
}
int FLunlinked(void *LD)
{ /* LD is never NULL! */
int *links = (int *) LD;
if (--*links)
return 0;
return 1;
}
main()
{
FlexL L1, L2;
char s[80];
if ((L1 = FLlinkInit(FLvariantNew(&FlexNodeStrVFT,
sizeof(int),FLunlinked))) == FlexL0)
return 1;
FLinsQD(L1,"one dog"); /* calls FNnew */
FLinsQD(L1,"two cats");
L2 = FLlink(L1);
FLinsQD(L2,"three crows");
FLvariantNew
while (FLnextD(L1,s)) /* calls FNread */
printf("\n%s",s);
FLstoreD(L2,"three cat birds",FLnodes(L2));
/* calls FNwrite which truncates! */
FLdelete(&L1); /* FLdelete fails */
printf("\nNodes in L1: %u",FLnodes(L1));
FLsort(L1,FLcomparE(strcmp));
FLmkcur(L2,0);
while (FLnextD(L2,s))
printf("\n%s",s);
FLdelete(&L2); /* Fldelete succeeds */
/* L2 is NULL now but not L1 */
L1 = FlexL0;
printf("\nNodes in L2: %u",FLnodes(L2));
return 0;
}
FLdelete has to be called twice to decrement the link
counter in the FlexList header via FLunlinked, the user
defined FLDdestruct function.
I skipped listing the virtual function definitions.
You can see them in the section on FLvariant or in the
flexlist.c source file.
FlexNodeStrVFT is the virtual function table that
contains pointers to the virtual functions that handle
C strings.
The FLcomparE macro, defined in flexlist.h, is used to
precisely type cast the user function pointer to the
type required by both FLsort and FLsetCompare.
Appendix A. Common Mistakes
Some common coding mistakes are listed below.
1. If you pass an address to a FlexList function of an item
other than the type for which the FlexList was constructed
for, data could be corrupted or the program may crash.
Suppose you call FLpopD with the address of a local variable
of the wrong type. If this variable is shorter in length
than what the FlexList expects, other data on C's stack
would be corrupted, perhaps the return address from that
function. If the FlexList functions were prototyped for
strong type checking, i.e. something other than "void *", to
avoid this, they would no longer be generic. Moral: you
must insure that the correct data types are used with their
respective FlexLists.
2. If the item itself, instead of its address, is passed to the
FlexList function, the item's contents will be wrongly
interpreted as the address to write to or read from. This
would result in writing good data to a wrong address or
copying garbage from a wrong address. This is obviously
undesirable!
3. It's sometimes easy to forget that the FLfixed, etc.,
constructor functions take the "sizeof" a type/variable
instead of a variable of that type. The compiler won't
catch it when your "FlexListing" integer types. The
FlexList will be wrongly initialized for the size of the
integer variable's value instead of the sizeof(integer
variable).
4. If your FNwrite virtual function, used with a variant
FlexList, overwrites the end of the FlexNode it will corrupt
other dynamically allocated memory. There is a remote
possibility that it may overwrite the C stack depending on
how your C compiler sets up the heap and stack.
5. With variant FlexLists, if the location you are copying data
to from a FlexNode isn't big enough to accommodate the
largest possible variant data, it of course will spill over
into other variables. If the location is a local variable,
the C stack will be corrupted with the results mentioned in
1 above.
6. When porting FlexList to various machines malloc can't
always allocate the full size of the maximum value that a
size_t variable can obtain. Be sure that FLmallocAlignLoss,
defined near the bottom of flexlist.h, is defined
appropriately.Appendix B.Inside FlexList
A FlexList has two data structures that provide the basis for all
operations.
1. A FlexNode has both next and previous FlexNode pointers.
The user data area is a character array of one byte. Actually
this field varies in length according to the value in the
sizeofNodeData field depicted in the FlexList header or as
determined by your FNnew virtual function. The void pointers
returned by FlexList functions point to the first byte of this
character array.
┌────────┐
FlexNode │ next ├────>
├────────┤
<────┤ prev │
├────────┤
│ data │ char [1]
└────────┘
2. The FlexList header contains data for controlling the list.
FlexList
┌────────────────┐
│ front │ ───> points to first FlexNode in list
├────────────────┤
│ current │ ───> points to last FlexNode accessed
├────────────────┤
│ rear │ ───> points to last FlexNode in list
├────────────────┤
│ curNum │ number of the current FlexNode
├────────────────┤
│ nodes │ number of FlexNodes in list
├────────────────┤
│ maxNodes │ maximum FlexNodes allowed
├────────────────┤
│ sizeofNodeData │ size of data in FlexNodes
├────────────────┤
│ sizeofNode │ size of FlexNodes with data
├────────────────┤
│ sorted │ is the FlexList sorted
├────────────────┤
│ compare │ function used to sort/match
├────────────────┤
│ vft │ ───> virtual function table
├────────────────┤
│ FLDdestruct │ destructor function for data
├────────────────┤
│ data │ 0 length unless user defined
└────────────────┘Consider the code listing below and the resultant data structure
from having executed this code. Several non pertinent fields of
the FlexList header have been left out of the figure.
{
FlexList l;
int i = 45;
FLfixed(&l,sizeof(int));
FLpushD(&l,&i);
i = 37;
FLinsQD(&l,&i);
FLmkcur(&l,1);
i = 29;
FLinsD(&l,&i);
}
FlexList ┌─────────────────────┐ FlexNode
│ ■
┌───────────────┐ │ ┌──────┐ ┌──────┐ ┌──────┐
│ front ├──┼────■│ next ├────■│ next ├───■│ next ├───┐
├───────────────┤ │ ├──────┤ ├──────┤ ├──────┤ ■
│ current ├──┘ ┌──┤ prev │■────┤ prev │■───┤ prev │
├───────────────┤ ■ ├──────┤ ├──────┤ ├──────┤
│ rear ├──┐ │ 45 │ │ 29 │ │ 37 │
├───────────────┤ │ └──────┘ └──────┘ └──────┘
│ curNum 2 │ │ ■
├───────────────┤ └──────────────────────────────────┘
│ nodes 3 │
├───────────────┤
│ sizeofN.D. 2 │
├───────────────┤
│ sizeofNode 6 │ ( 2 byte pointers )
├───────────────┤
│ vft ├──┐
└───────────────┘ │
■ (NULL)
The FlexList functions use the data in the FlexList header to
adjust their various operations, e.g. allocating, copying,
deallocating, etc., for the type of data that is being
warehoused.
Consider the code listing below and the resultant data structure
from having executed this code. Several non pertinent fields of
the FlexList header have been left out of the figure.
{
FlexList l;
FLstr(&l);
FLinsD(&l,"flex");
FLpushD(&l,"Hello");
FLinsQD(&l,"world!");
}
FlexList ┌─────────────────────┐ FlexNode
│ ■
┌───────────────┐ │ ┌──────┐ ┌──────┐ ┌──────┐
│ front ├──┼────■│ next ├────■│ next ├───■│ next ├───┐
├───────────────┤ │ ├──────┤ ├──────┤ ├──────┤ ■
│ current ├──┘ ┌──┤ prev │■────┤ prev │■───┤ prev │
├───────────────┤ ■ ├──────┤ ├──────┤ ├──────┤
│ rear ├──┐ │ H │ │ f │ │ w │
├───────────────┤ │ │ e │ │ l │ │ o │
│ curNum 2 │ │ │ l │ │ e │ │ r │
├───────────────┤ │ │ l │ │ x │ │ l │
│ nodes 3 │ │ │ o │ │ \0 │ │ d │
├───────────────┤ │ │ \0 │ └──────┘ │ ! │
│ sizeofN.D. 0 │ │ └──────┘ │ \0 │
├───────────────┤ │ └──────┘
│ sizeofNode 0 │ │ ■
├───────────────┤ └──────────────────────────────────┘
│ vft ├──┐
└───────────────┘ │ FlexNodeVFT
│
│ ┌────────────┐
└──■│ FNnew │
├────────────┤
│ FNwrite │
├────────────┤
│ FNread │
├────────────┤
│ FNdestruct │
└────────────┘
The FlexList functions use the FlexNodeVFT function pointers to
handle the variant length C strings, e.g. allocating, copying,
deallocating, etc.
Consider the code listing below and the resultant data structure
from having executed this code.
{
FlexL L;
L = FLfixedNew(sizeof(int),strlen("Hello")+1,
FLDdestruct0);
if (L)
strcpy(FLData(L),"Hello");
}
FlexList
┌───────────────────┐
│ front ├────────────┐
├───────────────────┤ │
│ current ├───────┐ ■
├───────────────────┤ │
│ rear ├────┐ ■
├───────────────────┤ │
│ curNum 0 │ ■
├───────────────────┤
│ nodes 0 │
├───────────────────┤
│ maxNodes 65535 │ largest unsigned ( 2 bytes )
├───────────────────┤
│ sizeofNodeData 2 │ ( 2 byte ints )
├───────────────────┤
│ sizeofNode 6 │ ( 2 byte pointers)
├───────────────────┤
│ sorted 1 │ zero nodes are always sorted!
├───────────────────┤
│ compare ├───────────┐
├───────────────────┤ │
│ vft ├───────┐ ■
├───────────────────┤ │
│ FLDdestruct ├────┐ ■
├───────────────────┤ │
│ H │ ■
│ e │
│ l │
│ l │
│ o │
│ \0 │
└───────────────────┘
The FlexList header itself can be enlarged to hold additional
data pertinent to the list overall. FLdelete calls your
FLDdestruct function with the starting address of "Hello" in this
case.
Appendix C. FlexList Source Code
/*
flexlist.h
10-4-90
Homogeneous-heterogeneous
hybrid stack-queue-list-array generic class.
ANSI C
Copyright 1990
John W. Small
All rights reserved
PSW / Power SoftWare
P.O. Box 10072
McLean, Virginia 22102 8072
(703) 759-3838
*/
/* LINTLIBRARY */
#ifndef FLEXLIST_ANSI_C
#define FLEXLIST_ANSI_C
#include <stddef.h> /* size_t */
#include <limits.h> /* UINT_MAX */
/* FlexNode declarations */
typedef struct FlexNode_ FlexNode, *FlexN;
#define FlexN0 ((FlexN)0)
#define FlexNodeLinkage FlexN next, prev
struct FlexNode_ {
/* friend: FlexList */
FlexNodeLinkage;
/* public: */
char data[1];
};
/* Virtual functions for variant FlexNodes */
typedef struct {
/* friend: FlexList */
FlexN (*FNnew)(const void *D);
int (*FNwrite)(void *ND, const void *D);
int (*FNread)(const void *ND, void *D);
int (*FNdestruct)(void *ND, void *D);
} FlexNodeVFT, *FlexNVFT;
#define FlexNVFT0 ((FlexNVFT)0)
#define FNnew0 ((FlexN (*)(const void *D)) 0)
#define FNwrite0 ((int (*)(void *ND, const void *D)) 0)
#define FNread0 ((int (*)(const void *ND, void *D)) 0)
#define FNdestruct0 ((int (*)(void *ND, void *D)) 0)
/* String variant FlexNode functions */
extern FlexNodeVFT FlexNodeStrVFT;
/* FlexList header declaration */
typedef struct {
/* private: */
FlexN front, current, rear;
unsigned curNum, nodes, maxNodes;
size_t sizeofNodeData, sizeofNode;
int sorted;
int (*compare)(const void *D1, const void *D2);
FlexNVFT vft;
int (*FLDdestruct)(void *LD);
char data[1];
} FlexList, *FlexL;
#define FlexL0 ((FlexL)0)
#define FLcomparE(compare) ((int (*)(const void *D1, \
const void *D2)) compare)
#define FLcompare0 FLcomparE(0)
#define FLDdestruct0 ((int (*)(void *LD)) 0)
/* FlexList constructors/destructor - static headers */
extern FlexL FLfixed(FlexL L, size_t sizeofNodeData);
extern FlexL FLunpack(FlexL L, size_t sizeofCell,
unsigned cells, const void *array);
extern FlexL FLvariant(FlexL L, FlexNVFT vft);
#define FLstr(L) FLvariant(L,&FlexNodeStrVFT)
extern int FLclear(FlexL L);
/* FlexList constructors/destructor - dynamic headers */
extern FlexL FLfixedNew(size_t sizeofNodeData,
size_t sizeofLocalData,
int (*FLDdestruct)(void *LD));
extern FlexL FLunpackNew(size_t sizeofCell,
unsigned cells, const void *array,
size_t sizeofLocalData,
int (*FLDdestruct)(void *LD));
extern FlexL FLvariantNew(FlexNVFT vft,
size_t sizeofLocalData,
int (*FLDdestruct)(void *LD));
#define FLstrNew(sizeofLocalData, FLDdestruct) \
FLvariantNew(&FlexNodeStrVFT, \
sizeofLocalData,FLDdestruct)
extern int FLdelete(FlexL *Lptr);
/* FlexList header functions */
#define FLfrontD(L) (void *)((L)? (L)->front? \
(L)->front->data : 0 : 0)
#define FLcurrentD(L) (void *)((L)? (L)->current? \
(L)->current->data : 0 : 0)
#define FLrearD(L) (void *)((L)? (L)->rear? \
(L)->rear->data : 0 : 0)
#define FLcurNum(L) ((L)? (L)->curNum : 0)
#define FLnodes(L) ((L)? (L)->nodes : 0)
#define FLmaxNodes(L) ((L)? (L)->maxNodes : 0)
extern int FLsetMaxNodes(FlexL L, unsigned maxNodes);
#define FLnotFull(L) ((L)? ((L)->maxNodes - (L)->nodes) : 0)
#define FLsizeofNodeData(L) ((L)? (L)->sizeofNodeData : 0)
#define FLisSorted(L) ((L)? (L)->sorted : 0)
#define FLunSort(L) ((L)? ((L)->sorted = 0, 1) : 0)
#define FLcompare(L) ((L)? (L)->compare : FLcompare0)
extern int FLsetCompare(FlexL L, int (*compare)
(const void *D1, const void *D2));
#define FLisFixed(L) FLsizeofNodeData(L)
#define FLisVariant(L) ((L)? !((L)->sizeofNodeData):0)
#define FLData(L) (void *)((L)? ((L)->FLDdestruct? \
(L)->data : 0) : 0)
/* FlexList stack and queue functions */
extern void *FLpushN(FlexL L, FlexN N);
extern void *FLpushD(FlexL L, const void *D);
extern FlexN FLpopN(FlexL L);
extern int FLpopD(FlexL L, void *D);
extern void *FLtopD(FlexL L, void *D);
extern void *FLinsQN(FlexL L, FlexN N);
extern void *FLinsQD(FlexL L, const void *D);
/* FlexList list functions */
extern void *FLmkcur(FlexL L, unsigned n);
extern void *FLinsN(FlexL L, FlexN N);
extern void *FLinsD(FlexL L, const void *D);
extern void *FLinsSortN(FlexL L, FlexN N);
extern void *FLinsSortD(FlexL L, const void *D);
extern FlexN FLdelN(FlexL L);
extern int FLdelD(FlexL L, void *D);
extern void *FLnextD(FlexL L, void *D);
extern void *FLprevD(FlexL L, void *D);
/* FlexList search/sort functions */
/* See also FLinsSortN()/FLinsSortD() list functions */
extern void *FLfindFirstD(FlexL L, const void *D);
extern void *FLfindNextD(FlexL L, const void *D);
extern void *FLfindLastD(FlexL L, const void *D);
extern void *FLfindPrevD(FlexL L, const void *D);
extern int FLsort(FlexL L, int (*compare)
(const void *D1, const void *D2));
/* FlexList array functions */
/* See also compaction functions */
extern int FLstoreD(FlexL L, const void *D, unsigned n);
extern int FLrecallD(FlexL L, void *D, unsigned n);
/* FlexList compaction functions */
/* See also FLunpack()/FLunpackNew() constructors */
extern void *FLpack(FlexL L);
extern void **FLpackPtrs(FlexL L);
/* FlexList implementation constants */
/* Change as required by target machine */
#define FLmaxMaxNodes UINT_MAX
#define FLmallocAlignLoss 16
#define FLmaxSizeofLocalData \
((size_t)(-(long)sizeof(FlexList) \
-FLmallocAlignLoss))
#define FLmaxSizeofNodeData \
((size_t)(-(long)sizeof(FlexNode) \
-FLmallocAlignLoss))
#define FLmaxSizeofArray \
((long)(size_t)-FLmallocAlignLoss)
#endif
/*
flexlist.c
10-4-90
Homogeneous-heterogeneous
hybrid stack-queue-list-array generic class.
ANSI C
Copyright 1990
John W. Small
All rights reserved
PSW / Power SoftWare
P.O. Box 10072,
McLean, Virginia 22102 8072
(703) 759-3838
*/
#include <flexlist.h> /* <stddef.h> size_t */
#include <stdlib.h> /* malloc(), free() */
#include <string.h> /* memcpy(), memset() */
/* String variant FlexNode virtual functions */
/*
FNnew() is called by FlexList functions (primitives)
that need to allocate new variant length FlexNodes,
e.g. FLpushD(), FLinsQD(), FLinsD(), FLinsSortD().
A pointer to the data to be placed in the new node
is passed to FNnew(). Your FNnew() function must
decide how large that data is and allocate a new
FlexNode big enough to hold that data, i.e.
FlexN N = malloc(sizeof(FlexNode) +
sizeofYourData - 1).
Your FNnew() function must also copy that data to
the new node. "D" is never NULL!
Please note that FNnew() could call a known function
pointer (function) in the data to determine its size.
It could also call another function to copy/
initialize the FlexNode data area from the data.
Data that contains its own functions for interfacing
with itself are called objects. Thus FlexLists can
be made to hold polymorphic objects via the
virtual function table functionology.
Study all four virtual functions FNnew(), FNwrite(),
FNread(), and FNdestruct() for strings and how they
are called by the various FlexList functions to get
a better understanding of variant FlexLists.
*/
static FlexN FNnewStr(const void *D)
{
FlexN N;
size_t i;
for (i = 0; ((char *)D)[i++]; /* no reinit */)
/* null statement */;
if ((N = malloc(sizeof(FlexNode)+i-1)) != FlexN0)
(void) memcpy(N->data,D,i);
return N;
}
/* FNwrite() is called by FLstoreD() to write variant data
to a variant FlexNode. Make sure the new data
doesn't write pass the end of the old. FNwrite()
returns true if the write is successful. "ND" and
"D" are never NULL! */
static int FNwriteStr(void *ND, const void *D)
{
char *nd, *d;
nd = (char *) ND;
d = (char *) D;
while (*nd)
if ((*nd++ = *d++) == '\0')
break;
return 1;
}
/* FNread() is called by FLtopD(), FLnextD(),
FLprevD(), and FLrecallD() to read variant data
from a variant FlexNode. FNread() returns true if
the read is successful. "ND" and "D" are never
NULL! */
static int FNreadStr(const void *ND, void *D)
{
char *nd, *d;
nd = (char *) ND;
d = (char *) D;
while ((*d++ = *nd++) != '\0')
/* null statement */;
return 1;
}
/* FNdestruct() is called by FLclear(), FLdelete() via
Flclear(), FLpopD(), and FLdelD() to destruct
variant data in a FlexNode. Please note that
references to suballocated memory may be copied
to the outgoing data structure instead of being
cloned and then deallocated. You must keep any
scheme straight though. FLclear() always passes
NULL to the second parameter of FNdestruct() via
a call to FLpopD(L,0), however, so any
suballocated memory must be freed in that case!
"ND" is never NULL but "D" can be! */
static int FNdestructStr(void *ND, void *D)
{
char *nd, *d;
nd = (char *)ND;
if ((d = (char *)D) != (char *)0)
while ((*d++ = *nd++) != '\0')
/* null statement */;
return 1;
}
/* Any of the virtual functions can be absent. The FlexList
functions that call them will simply return a failure
indication. Use FNnew0, FNwrite0, FNread0, and/or
FNdestruct0 as zero initializers. */
FlexNodeVFT FlexNodeStrVFT = {
FNnewStr, FNwriteStr, FNreadStr, FNdestructStr };
/* FlexList constructors/destructor - static headers */
#define FLzero(L) memset((void *)(L),0,sizeof(FlexList)-1)
FlexL FLfixed(FlexL L, size_t sizeofNodeData)
{
if (!L)
return L;
(void) FLzero(L);
if (!sizeofNodeData || sizeofNodeData
> FLmaxSizeofNodeData)
return FlexL0;
L->maxNodes = FLmaxMaxNodes;
L->sizeofNodeData = sizeofNodeData;
L->sizeofNode = sizeof(FlexNode)
+ sizeofNodeData - 1;
L->sorted = 1;
return L;
}
FlexL FLunpack(FlexL L, size_t sizeofCell,
unsigned cells, const void *array)
{
if (!L)
return L;
(void) FLzero(L);
if ((sizeofCell > FLmaxSizeofNodeData) ||
!sizeofCell || !cells || !array)
return FlexL0;
L->maxNodes = FLmaxMaxNodes;
L->sizeofNodeData = sizeofCell;
L->sizeofNode = sizeof(FlexNode)
+ sizeofCell - 1;
for (;cells && FLinsQD(L,array); cells--)
array = (char *) array + sizeofCell;
return L;
}
FlexL FLvariant(FlexL L, FlexNVFT vft)
{
if (!L)
return L;
(void) FLzero(L);
if (!vft)
return FlexL0;
L->maxNodes = FLmaxMaxNodes;
L->sorted = 1;
L->vft = vft;
return L;
}
int FLclear(FlexL L)
{
while (FLpopD(L,(void *)0))
/* null statement */;
if (L) if (!L->nodes)
return (L->sorted = 1);
return 0;
}
/* FlexList constructors/destructor - dynamic headers */
/* FlexList headers are flagged as dynamic if and only if
FLDdestruct != NULL. FLDmalloced() is the default
function pointer whenever one isn't specified. */
#pragma argsused
/* ARGSUSED */
static int FLDmalloced(void *LD)
{ /* LD is intentionally unused! */
return 1;
}
static FlexL FLnew(size_t sizeofLocalData,
int (*FLDdestruct)(void *LD))
{
FlexL L;
if (sizeofLocalData > FLmaxSizeofLocalData)
return FlexL0;
L = (FlexL) malloc(sizeof(FlexList) +
sizeofLocalData - 1);
if (L) {
(void) FLzero(L);
if (FLDdestruct)
L->FLDdestruct = FLDdestruct;
else
L->FLDdestruct = FLDmalloced;
}
return L;
}
FlexL FLfixedNew(size_t sizeofNodeData,
size_t sizeofLocalData,
int (*FLDdestruct)(void *LD))
{
FlexL L;
if (!sizeofNodeData || sizeofNodeData >
FLmaxSizeofNodeData)
return FlexL0;
if ((L = FLnew(sizeofLocalData,FLDdestruct))
!= FlexL0) {
L->maxNodes = FLmaxMaxNodes;
L->sizeofNodeData = sizeofNodeData;
L->sizeofNode = sizeof(FlexNode)
+ sizeofNodeData - 1;
L->sorted = 1;
}
return L;
}
FlexL FLunpackNew(size_t sizeofCell,
unsigned cells, const void *array,
size_t sizeofLocalData,
int (*FLDdestruct)(void *LD))
{
FlexL L;
if ((sizeofCell > FLmaxSizeofNodeData) ||
!sizeofCell || !cells || !array)
return FlexL0;
if ((L = FLnew(sizeofLocalData,FLDdestruct))
!= FlexL0) {
L->maxNodes = FLmaxMaxNodes;
L->sizeofNodeData = sizeofCell;
L->sizeofNode = sizeof(FlexNode)
+ sizeofCell - 1;
for (;cells && FLinsQD(L,array); cells--)
array = (char *) array + sizeofCell;
}
return L;
}
FlexL FLvariantNew(FlexNVFT vft,
size_t sizeofLocalData,
int (*FLDdestruct)(void *LD))
{
FlexL L;
if (!vft)
return FlexL0;
if ((L = FLnew(sizeofLocalData,FLDdestruct))
!= FlexL0) {
L->maxNodes = FLmaxMaxNodes;
L->sorted = 1;
L->vft = vft;
}
return L;
}
int FLdelete(FlexL *Lptr)
{
if (!Lptr)
return 0;
if (!(*Lptr)->FLDdestruct)
return 0;
if (!(*((*Lptr)->FLDdestruct))((*Lptr)->data))
return 0;
if (!FLclear(*Lptr))
return 0;
free(*Lptr);
*Lptr = FlexL0;
return 1;
}
/* FlexList header functions */
int FLsetMaxNodes(FlexL L, unsigned maxNodes)
{
if (L)
if (maxNodes >= L->nodes) {
L->maxNodes = maxNodes;
return 1;
}
return 0;
}
int FLsetCompare(FlexL L, int (*compare)
(const void *D1, const void *D2))
{
if (L) {
L->compare = compare;
L->sorted = 0;
return 1;
}
return 0;
}
/* FlexList stack and queue functions */
void * FLpushN(FlexL L, FlexN N)
{
if (!L || !N)
return (void *) 0;
if (L->nodes >= L->maxNodes)
return (void *) 0;
N->prev = FlexN0;
if ((N->next = L->front) != FlexN0)
N->next->prev = N;
else
L->rear = N;
L->front = N;
L->nodes++;
if (L->curNum)
L->curNum++;
L->sorted = 0;
return N->data;
}
void * FLpushD(FlexL L, const void *D)
{
FlexN N;
if (!L)
return (void *) 0;
if (L->nodes >= L->maxNodes)
return (void *) 0;
if (L->sizeofNode) { /* fixed size FlexNodes */
if ((N = malloc(L->sizeofNode)) == FlexN0)
return (void *) 0;
if (D)
memcpy(N->data,D,L->sizeofNodeData);
else
memset(N->data,0,L->sizeofNodeData);
}
else if (!L->vft || !D)
return (void *) 0;
else if (!L->vft->FNnew)
return (void *) 0;
else if ((N = (*L->vft->FNnew)(D)) == FlexN0)
return (void *) 0;
N->prev = FlexN0;
if ((N->next = L->front) != FlexN0)
N->next->prev = N;
else
L->rear = N;
L->front = N;
L->nodes++;
if (L->curNum)
L->curNum++;
L->sorted = 0;
return N->data;
}
FlexN FLpopN(FlexL L)
{
FlexN N;
if (!L)
return FlexN0;
if ((N = L->front) == FlexN0)
return FlexN0;
if (L->front == L->rear)
L->rear = FlexN0;
else
N->next->prev = FlexN0;
L->front = N->next;
L->nodes--;
if (L->curNum)
if (!--L->curNum)
L->current = FlexN0;
N->next = N->prev = FlexN0;
return N;
}
int FLpopD(FlexL L, void *D)
{
FlexN N;
if (!L)
return 0;
if ((N = L->front) == FlexN0)
return 0;
if (L->sizeofNodeData) {
if (D)
memcpy(D,N->data,L->sizeofNodeData);
}
else if (!L->vft)
return 0;
else if (!L->vft->FNdestruct)
return 0;
else if (!(*L->vft->FNdestruct)(N->data,D))
return 0;
if (L->front == L->rear)
L->rear = FlexN0;
else
N->next->prev = FlexN0;
L->front = N->next;
L->nodes--;
if (L->curNum)
if (!--L->curNum)
L->current = FlexN0;
free(N);
return 1;
}
void * FLtopD(FlexL L, void *D)
{
if (!L)
return (void *) 0;
if (!L->front)
return (void *) 0;
if (D) if (L->sizeofNodeData)
memcpy(D,L->front->data,L->sizeofNodeData);
else if (!L->vft)
return (void *) 0;
else if (!L->vft->FNread)
return (void *) 0;
else if (!(*L->vft->FNread)(L->front->data,D))
return (void *) 0;
return L->front->data;
}
void * FLinsQN(FlexL L, FlexN N)
{
if (!L || !N)
return (void *) 0;
if (L->nodes >= L->maxNodes)
return (void *) 0;
N->next = FlexN0;
if (L->rear)
L->rear->next = N;
else
L->front = N;
N->prev = L->rear;
L->rear = N;
L->nodes++;
L->sorted = 0;
return N->data;
}
void * FLinsQD(FlexL L, const void *D)
{
FlexN N;
if (!L)
return (void *) 0;
if (L->nodes >= L->maxNodes)
return (void *) 0;
if (L->sizeofNode) { /* fixed size FlexNodes */
if ((N = malloc(L->sizeofNode)) == FlexN0)
return (void *) 0;
if (D)
memcpy(N->data,D,L->sizeofNodeData);
else
memset(N->data,0,L->sizeofNodeData);
}
else if (!L->vft || !D)
return (void *) 0;
else if (!L->vft->FNnew)
return (void *) 0;
else if ((N = (*L->vft->FNnew)(D)) == FlexN0)
return (void *) 0;
N->next = FlexN0;
if (L->rear)
L->rear->next = N;
else
L->front = N;
N->prev = L->rear;
L->rear = N;
L->nodes++;
L->sorted = 0;
return N->data;
}
void * FLmkcur(FlexL L, unsigned n)
{
if (!L) return (void *) 0;
if (!n || (n > L->nodes)) { /* out of range */
L->current = 0;
L->curNum = 0;
return (void *) 0;
}
else if (n == L->curNum) /* already there */
return L->current->data;
if (L->current) /* divide list into two parts */
if (n > L->curNum) /* in last half of list */
if (((L->nodes >> 1) + (L->curNum >> 1)) < n)
/* rear closest */
for (L->current = L->rear, L->curNum = L->nodes;
L->curNum > n; L->curNum--)
L->current = L->current->prev;
else /* current closest */
for (;L->curNum < n; L->curNum++)
L->current = L->current->next;
else /* in first half of list */
if ((L->curNum >> 1) < n) /* current closest */
for (;L->curNum > n; L->curNum--)
L->current = L->current->prev;
else /* front closest */
for (L->current = L->front, L->curNum = 1;
L->curNum < n; L->curNum++)
L->current = L->current->next;
else /* consider whole list */
if ((L->nodes >> 1) < n) /* closer to rear */
for (L->current = L->rear, L->curNum = L->nodes;
L->curNum > n; L->curNum--)
L->current = L->current->prev;
else /* closer to front */
for (L->current = L->front, L->curNum = 1;
L->curNum < n; L->curNum++)
L->current = L->current->next;
return L->current->data;
}
void * FLinsN(FlexL L, FlexN N)
{
if (!L || !N)
return (void *) 0;
if (L->nodes >= L->maxNodes)
return (void *) 0;
if ((N->prev = L->current) == FlexN0) {
if ((N->next = L->front) == FlexN0)
L->rear = N;
else
N->next->prev = N;
L->front = N;
}
else { /* after current */
if ((N->next = L->current->next) == FlexN0)
L->rear = N; /* last node */
else
N->next->prev = N;
L->current->next = N;
}
L->current = N;
L->curNum++;
L->nodes++;
L->sorted = 0;
return N->data;
}
void * FLinsD(FlexL L, const void *D)
{
FlexN N;
if (!L)
return (void *) 0;
if (L->nodes >= L->maxNodes)
return (void *) 0;
if (L->sizeofNode) { /* fixed size FlexNodes */
if ((N = malloc(L->sizeofNode)) == FlexN0)
return (void *) 0;
if (D)
memcpy(N->data,D,L->sizeofNodeData);
else
memset(N->data,0,L->sizeofNodeData);
}
else if (!L->vft || !D)
return (void *) 0;
else if (!L->vft->FNnew)
return (void *) 0;
else if ((N = (*L->vft->FNnew)(D)) == FlexN0)
return (void *) 0;
if ((N->prev = L->current) == FlexN0) {
if ((N->next = L->front) == FlexN0)
L->rear = N;
else
N->next->prev = N;
L->front = N;
}
else { /* after current */
if ((N->next = L->current->next) == FlexN0)
L->rear = N; /* last node */
else
N->next->prev = N;
L->current->next = N;
}
L->current = N;
L->curNum++;
L->nodes++;
L->sorted = 0;
return N->data;
}
void * FLinsSortN(FlexL L, FlexN N)
{
unsigned long low, high;
void *ok;
if (!L || !N)
return (void *) 0;
if (L->nodes >= L->maxNodes || !L->compare)
return (void *) 0;
if (!L->sorted)
(void) FLsort(L,FLcompare0);
low = 1UL;
high = (unsigned long) L->nodes;
while (low <= high)
if ((*L->compare)(FLmkcur(L,
(unsigned)((low+high) >> 1)),
N->data) <= 0)
low = (unsigned long)
(L->curNum + 1);
else
high = (unsigned long)
(L->curNum - 1);
(void) FLmkcur(L,(unsigned)high);
ok = FLinsN(L,N);
L->sorted = 1;
return ok;
}
void * FLinsSortD(FlexL L, const void *D)
{
FlexN N;
unsigned long low, high;
void *ok;
if (!L || !D)
return (void *) 0;
if (L->nodes >= L->maxNodes || !L->compare)
return (void *) 0;
if (L->sizeofNode) { /* fixed size FlexNodes */
if ((N = malloc(L->sizeofNode)) == FlexN0)
return (void *) 0;
memcpy(N->data,D,L->sizeofNodeData);
}
else if (!L->vft)
return (void *) 0;
else if (!L->vft->FNnew)
return (void *) 0;
else if ((N = (*L->vft->FNnew)(D)) == FlexN0)
return (void *) 0;
if (!L->sorted)
(void) FLsort(L,FLcompare0);
low = 1UL;
high = (unsigned long) L->nodes;
while (low <= high)
if ((*L->compare)(FLmkcur(L,
(unsigned)((low+high) >> 1)),
N->data) <= 0)
low = (unsigned long)
(L->curNum + 1);
else
high = (unsigned long)
(L->curNum - 1);
(void) FLmkcur(L,(unsigned)high);
ok = FLinsN(L,N);
L->sorted = 1;
return ok;
}
FlexN FLdelN(FlexL L)
{
FlexN N;
if (!L)
return FlexN0;
if ((N = L->current) == FlexN0)
return FlexN0;
L->current = N->prev;
L->curNum--;
if (N->next)
N->next->prev = N->prev;
else
L->rear = N->prev;
if (N->prev)
N->prev->next = N->next;
else
L->front = N->next;
L->nodes--;
N->next = N->prev = FlexN0;
return N;
}
int FLdelD(FlexL L, void *D)
{
FlexN N;
if (!L)
return 0;
if ((N = L->current) == FlexN0)
return 0;
if (L->sizeofNodeData) {
if (D)
memcpy(D,N->data,L->sizeofNodeData);
}
else if (!L->vft)
return 0;
else if (!L->vft->FNdestruct)
return 0;
else if (!(*L->vft->FNdestruct)(N->data,D))
return 0;
L->current = N->prev;
L->curNum--;
if (N->next)
N->next->prev = N->prev;
else
L->rear = N->prev;
if (N->prev)
N->prev->next = N->next;
else
L->front = N->next;
L->nodes--;
free(N);
return 1;
}
void * FLnextD(FlexL L, void *D)
{
FlexN oldCurrent;
if (!L)
return (void *) 0;
if ((oldCurrent = L->current) != FlexN0)
L->current = L->current->next;
else
L->current = L->front;
if (!L->current) {
L->curNum = 0;
return (void *) 0;
}
if (D) if (L->sizeofNodeData)
memcpy(D,L->current->data,
L->sizeofNodeData);
else if (!L->vft) {
L->current = oldCurrent;
return (void *) 0;
}
else if (!L->vft->FNread) {
L->current = oldCurrent;
return (void *) 0;
}
else if (!(*L->vft->FNread)(L->current->data,D)) {
L->current = oldCurrent;
return (void *) 0;
}
L->curNum++;
return L->current->data;
}
void * FLprevD(FlexL L, void *D)
{
FlexN oldCurrent;
unsigned oldCurNum;
if (!L)
return (void *) 0;
oldCurNum = L->curNum;
if ((oldCurrent = L->current) != FlexN0) {
L->current = L->current->prev;
L->curNum--;
}
else {
L->current = L->rear;
L->curNum = L->nodes;
}
if (!L->current)
return (void *) 0;
if (D) if (L->sizeofNodeData)
memcpy(D,L->current->data,
L->sizeofNodeData);
else if (!L->vft) {
L->curNum = oldCurNum;
L->current = oldCurrent;
return (void *) 0;
}
else if (!L->vft->FNread) {
L->curNum = oldCurNum;
L->current = oldCurrent;
return (void *) 0;
}
else if (!(*L->vft->FNread)(L->current->data,D)) {
L->curNum = oldCurNum;
L->current = oldCurrent;
return (void *) 0;
}
return L->current->data;
}
void * FLfindFirstD(FlexL L, const void *D)
{
unsigned long low, high;
if (!L || !D)
return (void *) 0;
if (!L->compare)
return (void *) 0;
if (L->sorted) {
low = 1UL;
high = (unsigned long) L->nodes;
while (low <= high)
if ((*L->compare)(FLmkcur(L,
(unsigned)((low+high) >> 1)),D) < 0)
low = (unsigned long) (L->curNum + 1);
else
high = (unsigned long) (L->curNum - 1);
if (FLmkcur(L,(unsigned)high+1))
if (!(*L->compare)(L->current->data,D))
return L->current->data;
/* leave at insertion point */
(void) FLmkcur(L,(unsigned)high);
}
else {
(void) FLmkcur(L,0);
while (FLnextD(L,(void *)0))
if (!(*L->compare)(L->current->data,D))
return L->current->data;
}
return (void *) 0;
}
void * FLfindNextD(FlexL L, const void *D)
{
if (!L || !D)
return (void *) 0;
if (!L->compare)
return (void *) 0;
while (FLnextD(L,(void *)0))
if (!(*L->compare)(L->current->data,D))
return L->current->data;
else if (L->sorted)
break;
return (void *) 0;
}
void * FLfindLastD(FlexL L, const void *D)
{
unsigned long low, high;
if (!L || !D)
return (void *) 0;
if (!L->compare)
return (void *) 0;
if (L->sorted) {
low = 1UL;
high = (unsigned long) L->nodes;
while (low <= high)
if ((*L->compare)(FLmkcur(L,
(unsigned)((low+high) >> 1)),D) <= 0)
low = (unsigned long) (L->curNum + 1);
else
high = (unsigned long) (L->curNum - 1);
if (FLmkcur(L,(unsigned)high))
if (!(*L->compare)(L->current->data,D))
return L->current->data;
}
else {
(void) FLmkcur(L,0);
while (FLprevD(L,(void *)0))
if (!(*L->compare)(L->current->data,D))
return L->current->data;
}
return (void *) 0;
}
void * FLfindPrevD(FlexL L, const void *D)
{
if (!L || !D)
return (void *) 0;
if (!L->compare)
return (void *) 0;
while (FLprevD(L,(void *)0))
if (!(*L->compare)(L->current->data,D))
return L->current->data;
else if (L->sorted)
break;
return (void *) 0;
}
int FLsort(FlexL L, int (*compare)
(const void *D1, const void *D2))
{
FlexList tmp;
if (!L)
return 0;
if (L->sorted) {
if (L->compare == compare || !compare)
{ FLmkcur(L,0); return 1; }
}
else if (!L->compare && !compare)
return 0;
if (compare)
L->compare = compare;
if (!L->nodes)
return (L->sorted = 1);
(void) FLzero(&tmp);
tmp.maxNodes = FLmaxMaxNodes;
tmp.sorted = 1;
tmp.compare = L->compare;
while (L->nodes)
(void) FLinsSortN(&tmp,FLpopN(L));
L->front = tmp.front;
L->rear = tmp.rear;
L->nodes = tmp.nodes;
return (L->sorted = 1);
}
int FLstoreD(FlexL L, const void *D, unsigned n)
{
unsigned oldn;
if (!L || !D)
return 0;
if (n > L->nodes || !n && !L->current)
return 0;
if (L->sizeofNodeData) {
if (n) (void) FLmkcur(L,n);
memcpy(L->current->data,D,
L->sizeofNodeData);
}
else if (!L->vft)
return 0;
else if (!L->vft->FNwrite)
return 0;
else {
oldn = L->curNum;
if (n) (void) FLmkcur(L,n);
if (!(*L->vft->FNwrite)(L->current->data,D))
{
(void) FLmkcur(L,oldn);
return 0;
}
}
L->sorted = 0;
return 1;
}
int FLrecallD(FlexL L, void *D, unsigned n)
{
unsigned oldn;
if (!L || !D)
return 0;
if (n > L->nodes || !n && !L->current)
return 0;
if (L->sizeofNodeData) {
if (n) (void) FLmkcur(L,n);
memcpy(D,L->current->data,
L->sizeofNodeData);
}
else if (!L->vft)
return 0;
else if (!L->vft->FNread)
return 0;
else {
oldn = L->curNum;
if (n) (void) FLmkcur(L,n);
if (!(*L->vft->FNread)(L->current->data,D))
{
(void) FLmkcur(L,oldn);
return 0;
}
}
return 1;
}
void * FLpack(FlexL L) /* Only fixed nodes! */
{
long sizeofArray;
char *A, *Ai;
FlexN N;
if (!L) return (void *) 0;
sizeofArray = ((long)L->sizeofNodeData)
* ((long)L->nodes);
if ((sizeofArray <= 0) ||
(sizeofArray > FLmaxSizeofArray))
return (void *) 0;
if ((A = malloc((unsigned) sizeofArray))
== (char *) 0)
return (void *) 0;
for (Ai = A, N = L->front; N; N = N->next,
Ai += L->sizeofNodeData)
memcpy(Ai,N->data,L->sizeofNodeData);
return A;
}
void **FLpackPtrs(FlexL L)
{
long sizeofArray;
void **A;
unsigned Ai;
FlexN N;
if (!L) return (void **) 0;
sizeofArray = sizeof(void *) * ((long)L->nodes + 1);
if ((sizeofArray <= 0) ||
(sizeofArray > FLmaxSizeofArray))
return (void **) 0;
if ((A = malloc((unsigned) sizeofArray))
== (void **) 0)
return (void **) 0;
for (Ai = 0, N = L->front; N; Ai++, N = N->next)
A[Ai] = N->data;
A[Ai] = (void *) 0;
return A;
}
Index
address of operator "&" 11,
13, 23, 25
array functions 14, 21, 26
binary search algorithm 19,
38, 51, 53, 75, 79
boolean return values 12,
18, 34
compaction 14, 21
compare function 18
compatible 24, 26, 57
constructors 11-14, 24, 25,
114, 115
curNum 109
current 109
current node 16-18, 21
C++ 9, 14
dangling 24, 26, 96, 99
data in
FlexList 112
FlexNode 110, 111
data pointer
see value, by
data length
see sizeofNodeData
destructors 12, 13, 14,
114, 115
different types of data 7,
11, 14, see heterogeneous
lists
doubly linked lists 16, 110
explicitly delete
FlexNodes 24, 26
other dynamic memory 21
exploding arrays into
FlexLists 14, 21
FLclear 14, 29, 114, 121
FLcomparE 20, 114
FLcompare 15, 16, 18, 30, 115
FLcompare0 19, 114
FLcurNum 15, 21, 32, 115
FLcurrentD 15, 16, 21, 33,
115
FLData 15, 34, 115
FLDdestruct 36, 42, 43, 114
FLDdestruct0 43, 114
FLdelD 35, 116, 135
FLdelete 14, 36, 115, 123
FLdelN 37, 116, 134
FlexL 13, 114
FlexL0 13, 114
FlexList
constructors 11-14, 24,
25, 114, 115
destructors 12, 13, 14,
114, 115
fields 109, 112
functions 25-26
header 14-15, 25, 109-
112
FlexN 113
FlexN0 95, 113
FlexNode 109-113
FlexNodeLinkage 109, 113
FlexNodeVFT 111, 113
FlexNVFT 57, 113
FlexNVFT0 57, 114
FLfindFirstD 18, 38, 116, 138
FLfindLastD 18, 38, 116, 139
FLfindNextD 18, 38, 116, 138
FLfindPrevD 18, 38, 116, 139
FLfixed 14, 41, 114, 120
FLfixedNew 14, 42, 115, 122
FLfrontD 15, 46, 115
FLinsD 16, 47, 116, 131
FLinsN 16, 48, 116, 130
FLinsQD 15, 49, 115, 128
FLinsQN 15, 50, 115, 127
FLinsSortD 16, 18, 51 116,
133
FLinsSortN 16, 18, 53, 116,
132
FLisFixed 15, 55, 115
FLisSorted 15, 56, 115
FLisVariant 15, 57, 115
FLmallocAlignLoss 107, 116
FLmaxMaxNodes 58, 116
FLmaxNodes 15, 58, 115
FLmkcur 16, 21, 59, 116, 129
FLnextD 16, 60, 116, 136
FLnodes 15, 61, 115
FLnotFull 15, 62, 115
FLpack 21, 63, 116, 142
FLpackPtrs 21, 65, 116, 143
FLpopD 15, 66, 115, 126
FLpopN 15, 67, 115, 126
FLprevD 15, 69, 116, 137
FLpushD 15, 70, 115, 125
FLpushN 15, 71, 115, 124
FLrearD 15, 72, 115
FLrecallD 21, 73, 116, 142
FLsetCompare 15, 16, 18,
75, 115, 124
FLsetMaxNodes 15, 77, 115,
123
FLsizeofNodeData 15, 78, 115
FLsort 18, 79, 116, 140
FLstoreD 21, 81, 116, 141
FLstr 14, 83, 114, see
FLvariant 93
FLstrNew 14, 85, 115
FLtopD 86, 115, 127, see
FLfrontD
FLunpack 14, 21, 87, 114,
120
FLunpackNew 14, 21, 88, 115,
122
FLunSort 15, 18, 19, 92, 115
FLvariant 14, 93, 114, 120
FLvariantNew 14, 102, 115,
123
FNdestruct 93, 114, 118
FNdestruct0 94, 114
FNnew 93, 113, 118
FNnew0 94, 114
FNread 93, 113, 118
FNread0 94, 114
FNwrite 93, 113, 118
FNwrite0 94, 114
front 109
general structure of a
FlexList 110-112
header functions 14-15, 25,
109-112
heterogeneous lists 7, 14,
see FLvariant
imploding FlexLists into
arrays 21
inhibit the copying of data
17, 26
initialize
see constructors
list functions 16, 26
maxNodes 109, 112
node, by 15, 23-24, 26
nodes 109, 112
OOP 4, 14
porting FlexList 107, 116
proprietary techniques 1
queue functions 15, 25
rear 109, 112
reference, by 23, 26
registration 3
run time 7
search algorithm, binary
see binary search ...
searching/sorting 18-19, 26
sequential access 16
sizeofNode 109, 112
sizeofNodeData 109, 112
software license 3
sorted 109, 112
sorting/searching
see searching/sorting
stack functions 15, 25
stack-queue-list-array hybrid
25-26, 110-111
unpacking/packing methods
see compaction
value, by 23, 26
variant list 14,
see FLvariant 93
vft 109, 112
virtual function table
112, see FlexNodeVFT
void pointer
see reference, by
warranty 3
----------------end-of-author's-documentation---------------
Software Library Information:
This disk copy provided as a service of
Public (software) Library
We are not the authors of this program, nor are we associated
with the author in any way other than as a distributor of the
program in accordance with the author's terms of distribution.
Please direct shareware payments and specific questions about
this program to the author of the program, whose name appears
elsewhere in this documentation. If you have trouble getting
in touch with the author, we will do whatever we can to help
you with your questions. All programs have been tested and do
run. To report problems, please use the form that is in the
file PROBLEM.DOC on many of our disks or in other written for-
mat with screen printouts, if possible. PsL cannot debug pro-
programs over the telephone, though we can answer questions.
Disks in the PsL are updated monthly, so if you did not get
this disk directly from the PsL, you should be aware that the
files in this set may no longer be the current versions. Also,
if you got this disk from another vendor and are having prob-
lems, be aware that some files may have become corrupted or
lost by that vendor. Get a current, working disk from PsL.
For a copy of the latest monthly software library newsletter
and a list of the 4,000+ disks in the library, call or write
Public (software) Library
P.O.Box 35705 - F
Houston, TX 77235-5705
1-800-2424-PSL
MC/Visa/AmEx/Discover
Outside of U.S. or in Texas
or for general information,
Call 1-713-524-6394